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 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