parent
3d157e51d8
commit
afa1d93212
@ -0,0 +1,150 @@
|
|||||||
|
//! Errno handling
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use std::{
|
||||||
|
error,
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
use libc::__errno_location;
|
||||||
|
use once_cell::sync::OnceCell;
|
||||||
|
|
||||||
|
const MESSAGE_BUF_SIZE: usize = 512;
|
||||||
|
|
||||||
|
/// Get `errno` value.
|
||||||
|
#[inline] pub fn raw() -> i32
|
||||||
|
{
|
||||||
|
unsafe{*__errno_location()}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_message(errno: i32) -> String
|
||||||
|
{
|
||||||
|
use libc::{
|
||||||
|
strerror_r,
|
||||||
|
};
|
||||||
|
|
||||||
|
use std::ffi::CStr;
|
||||||
|
|
||||||
|
let mut buffer = [0u8; MESSAGE_BUF_SIZE+1];
|
||||||
|
let cstr = unsafe {
|
||||||
|
strerror_r(errno, &mut buffer[0] as *mut u8 as *mut libc::c_char, MESSAGE_BUF_SIZE);
|
||||||
|
CStr::from_ptr(&buffer[0] as *const u8 as *const libc::c_char)
|
||||||
|
};
|
||||||
|
|
||||||
|
cstr.to_string_lossy().into_owned()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// Errno wrapper for Rust errors
|
||||||
|
pub struct Errno<T>
|
||||||
|
where T: fmt::Debug
|
||||||
|
{
|
||||||
|
errno: i32,
|
||||||
|
msg: OnceCell<String>,
|
||||||
|
pub internal: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Errno<T>
|
||||||
|
where T: error::Error + 'static
|
||||||
|
{
|
||||||
|
/// Get the message for this errno
|
||||||
|
pub fn message(&self) -> &str
|
||||||
|
{
|
||||||
|
&self.msg.get_or_init(|| get_message(self.errno))[..]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the errno of this instance
|
||||||
|
pub fn error(&self) -> i32
|
||||||
|
{
|
||||||
|
self.errno
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume this instance, returning the wrapped value
|
||||||
|
pub fn into_inner(self) -> T
|
||||||
|
{
|
||||||
|
self.internal
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Map the inner value
|
||||||
|
pub fn map_inner<U,F>(self, fun: F) -> Errno<U>
|
||||||
|
where F: FnOnce(T) -> U,
|
||||||
|
U: error::Error + 'static
|
||||||
|
{
|
||||||
|
Errno {
|
||||||
|
internal: fun(self.internal),
|
||||||
|
errno: self.errno,
|
||||||
|
msg: self.msg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if this `errno` value is 0 (`Success`)
|
||||||
|
pub fn is_success(&self) -> bool
|
||||||
|
{
|
||||||
|
self.errno == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::error::Error for Errno<T>
|
||||||
|
where T: error::Error + 'static
|
||||||
|
{
|
||||||
|
fn source(&self) -> Option<&(dyn error::Error + 'static)>
|
||||||
|
{
|
||||||
|
Some(&self.internal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> std::fmt::Display for Errno<T>
|
||||||
|
where T: error::Error + 'static
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
write!(f, "{}: {} ({})", self.internal, self.message(), self.errno)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Errno<T>
|
||||||
|
where T: error::Error + 'static
|
||||||
|
{
|
||||||
|
/// Create a new errno wrapper with specific `errno` value
|
||||||
|
pub fn with_errno(err: T, errno: i32) -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
errno,
|
||||||
|
msg: OnceCell::new(),
|
||||||
|
internal: err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Create a new errno wrapper with the current `errno` value
|
||||||
|
#[inline] pub fn new(err: T) -> Self
|
||||||
|
{
|
||||||
|
Self::with_errno(err, raw())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for Errno<T>
|
||||||
|
where T: error::Error + 'static
|
||||||
|
{
|
||||||
|
#[inline] fn from(from: T) -> Self
|
||||||
|
{
|
||||||
|
Self::new(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ResultExt<T,V>
|
||||||
|
{
|
||||||
|
/// Call `map_inner()` on the inner error of `Errno<T>` if it is `Err`, otherwise return the same `Ok`.
|
||||||
|
fn map_inner<U,F>(self, fun: F) -> Result<V,Errno<U>>
|
||||||
|
where F: FnOnce(T) -> U,
|
||||||
|
U: error::Error + 'static;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T,V> ResultExt<T,V> for Result<V,Errno<T>>
|
||||||
|
where T: error::Error + 'static
|
||||||
|
{
|
||||||
|
fn map_inner<U,F>(self, fun: F) -> Result<V,Errno<U>>
|
||||||
|
where F: FnOnce(T) -> U,
|
||||||
|
U: error::Error + 'static
|
||||||
|
{
|
||||||
|
self.map_err(|e| e.map_inner(fun))
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,105 @@
|
|||||||
//! `pipe()` wrapper
|
//! `pipe()` related operations
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use errno::Errno;
|
||||||
|
use std::{
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Represents an error on `pipe()` related operations
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
|
||||||
|
Create,
|
||||||
|
Read,
|
||||||
|
Write,
|
||||||
|
Broken,
|
||||||
|
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
impl std::error::Error for Error{}
|
||||||
|
impl std::fmt::Display for Error
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Create => write!(f, "failed to create pipe"),
|
||||||
|
Self::Read => write!(f, "failed to read from pipe"),
|
||||||
|
Self::Write => write!(f, "failed to write to pipe"),
|
||||||
|
Self::Broken => write!(f, "broken pipe"),
|
||||||
|
_ => write!(f, "unknown error"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create with `pipe()`
|
||||||
|
pub(super) fn unix_pipe() -> Result<(i32,i32), Errno<Error>>
|
||||||
|
{
|
||||||
|
use libc::{
|
||||||
|
pipe,
|
||||||
|
};
|
||||||
|
let mut pipe_fd: [libc::c_int; 2] = [0;2];
|
||||||
|
if unsafe{pipe(&mut pipe_fd[0] as *mut libc::c_int)} == 0{
|
||||||
|
Ok((pipe_fd[0], pipe_fd[1]))
|
||||||
|
} else {
|
||||||
|
Err(Error::Create.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write to a pipe
|
||||||
|
pub(super) fn pipe_write(output: i32, buf: impl AsRef<[u8]>) -> Result<usize, Errno<Error>>
|
||||||
|
{
|
||||||
|
let buf = buf.as_ref();
|
||||||
|
let len = buf.len();
|
||||||
|
|
||||||
|
let read = unsafe{libc::write(output, &buf[0] as *const u8 as *const libc::c_void, len)};
|
||||||
|
|
||||||
|
if read < 0 {
|
||||||
|
Err(Error::Write.into())
|
||||||
|
} else {
|
||||||
|
Ok(read as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub(super) fn pipe_read(input: i32, mut buf: impl AsMut<[u8]>) -> Result<usize, Errno<Error>>
|
||||||
|
{
|
||||||
|
let buf = buf.as_mut();
|
||||||
|
let len = buf.len();
|
||||||
|
|
||||||
|
let read = unsafe{libc::read(input, &mut buf[0] as *mut u8 as *mut libc::c_void, len)};
|
||||||
|
|
||||||
|
if read < 0 {
|
||||||
|
Err(Error::Read.into())
|
||||||
|
} else {
|
||||||
|
Ok(read as usize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn pipe_write_value<T: ?Sized>(fd: i32, value: &T) -> Result<(), Errno<Error>>
|
||||||
|
{
|
||||||
|
let sz = std::mem::size_of_val(value);
|
||||||
|
|
||||||
|
let write = pipe_write(fd, std::slice::from_raw_parts(value as *const T as *const u8, sz))?;
|
||||||
|
if write == sz {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(Error::Broken.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) unsafe fn pipe_read_value<T>(fd: i32) -> Result<T, Errno<Error>>
|
||||||
|
{
|
||||||
|
use malloc_array::heap;
|
||||||
|
|
||||||
|
let mut buf = heap![unsafe 0u8; std::mem::size_of::<T>()];
|
||||||
|
|
||||||
|
let read = pipe_read(fd, &mut buf)?;
|
||||||
|
|
||||||
|
if read == buf.len() {
|
||||||
|
let ptr = buf.reinterpret::<T>();
|
||||||
|
Ok(ptr.as_ptr().read())
|
||||||
|
} else {
|
||||||
|
Err(Error::Broken.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in new issue