mapped-file 0.0.8

Construct a memory mapping over any file object
Documentation
//! Useful for C-interop
use super::*;

macro_rules! c_try {
    ($call:expr => $invalid:literal; $fmt:literal $(, $args:expr)*) => {
	{
            #[inline(never)]
            #[cold]
            fn _panic_bad_c_call<'a>(args: ::std::fmt::Arguments<'a>) -> !
            {
		panic!("C call failed (invalid return {}): {}", $invalid, args)
            }

	    #[allow(unused_unsafe)]
	    let res = unsafe { $call };
	    if res == $invalid {
		_panic_bad_c_call(format_args!($fmt $(, $args)*))
	    }
	    res
	}
    };
    ($call:expr => if $func:expr; $fmt:literal $(, $args:expr)*) => {
	{
	    #[inline(never)]
            #[cold]
            fn _panic_bad_c_call<'a, T: ::std::fmt::Display>(invalid: T, args: ::std::fmt::Arguments<'a>) -> !
            {
		panic!("C call failed (invalid return {}): {}", invalid, args)
            }
	    #[allow(unused_unsafe)]
	    let res = unsafe { $call };
	    if $func(res) {
		_panic_bad_c_call(res, format_args!($fmt $(, $args)*));
	    }
	    res
	}
    };
    (? $call:expr => if $func:expr; $fmt:literal $(, $args:expr)*) => {
	{
	    #[allow(unused_unsafe)]
	    let res = unsafe { $call };
	    if $func(res) {
		Err(FFIError::from_last_error(res, format_args!($fmt $(, $args)*)))
	    } else {
		Ok(res)
	    }
	}
    };
    (? $call:expr => $invalid:literal; $fmt:literal $(, $args:expr)*) => {
	{
	    #[allow(unused_unsafe)]
	    let res = unsafe { $call };
	    if res == $invalid {
		Err(FFIError::from_last_error($invalid, format_args!($fmt $(, $args)*)))
	    } else {
		Ok(res)
	    }
	}
    };
    /* Eh... Idk why this doesn't work...
    ($call:expr => {$($invalid:pat $(if $pred:pat)?),+} => $fmt:literal $(, $args:expr)*) => {
    {
    #[inline(never)]
    #[cold]
    fn _panic_bad_c_call<'a, T: ::std::fmt::Display>(invalid: T, args: ::std::fmt::Arguments<'a>) -> !
    {
    panic!("C call failed (invalid return {}): {}", invalid, args)
}
    let res = $call;
    match res {
    $($invalid $(if $pred)? => _panic_bad_c_call(res, format_args!($fmt $(, $args)*))),*
    x => x,
}
}
};*/
}
pub(crate) use c_try;

/// Error context for a failed C call.
/// Returns the invalid return value, the `errno` error, and a message.
#[derive(Debug)]
pub struct FFIError<'a, T>(T, io::Error, fmt::Arguments<'a>);

impl<'a, T> FFIError<'a, T>
where FFIError<'a, T>: error::Error
{
    #[inline(never)]
    #[cold]
    fn from_last_error(value: T, arguments: fmt::Arguments<'a>) -> Self
    {
	Self(value, io::Error::last_os_error(), arguments)
    }   
}
    

impl<'a, T> AsRef<io::Error> for FFIError<'a, T>
{
    #[inline]
    fn as_ref(&self) -> &io::Error {
	&self.1
    }
}

impl<'a, T> FFIError<'a, T>
{
    /// A reference to the value
    #[inline] 
    pub fn value(&self) -> &T
    {
	&self.0
    }

    /// Clone an instance of the value
    #[inline] 
    pub fn to_value(&self) -> T
    where T: Clone
    {
	self.0.clone()
    }

    /// Consume into the value
    #[inline] 
    pub fn into_value(self) -> T
    {
	self.0
    }


    /// Consume into a recursive 2-tuple of `((value, error), message)`.
    #[inline] 
    pub fn into_parts(self) -> ((T, io::Error), impl fmt::Display + fmt::Debug + 'a)
    {
	((self.0, self.1), self.2)
    }

    /// A reference to the inner OS error
    #[inline] 
    pub fn error(&self) -> &io::Error
    {
	&self.1
    }

    /// Get a reference to an opaque type that can be formatted into the message
    #[inline] 
    pub fn message(&self) -> &(impl fmt::Display + fmt::Debug + 'a)
    {
	&self.2
    }

    /// Consume an opaque type that can be formatted into the message
    pub fn into_message(self) -> impl fmt::Display + fmt::Debug + 'a
    {
	self.2
    }
/* This doesn't work...
    /// Render any referenced arguments in the message into a string, reducing the lifetime requirement of the message to `'static`.
    ///
    /// # Notes
    /// If `T` is not also `'static`, then the resulting instance will not be `'static` itself. If `T` is not `'static`, use `into_owned()` instead.
    #[inline] 
    pub fn message_into_owned(self) -> FFIError<'static, T>
    {
	FFIError(self.0, self.1, format_args!("{}", self.2.to_string()))
    }

    /// Clone any referenced arguments of the message and the value into a non-referential object, reducing the lifetime requirements of the returned instance to `'static`.
    #[inline] 
    pub fn into_owned(self) -> FFIError<'static, T::Owned>
    where T: ToOwned,
    T::Owned: 'static
    {
	FFIError(self.0.to_owned(), self.1, format_args!("{}", self.2.to_string()))
}
    */
}

impl<'a, T> error::Error for FFIError<'a, T>
where FFIError<'a, T>: fmt::Display + fmt::Debug
{
    #[inline] 
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
	Some(&self.1)
    }
}
impl<'a, T: fmt::Debug> fmt::Display for FFIError<'a, T>
{
    #[inline] 
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
    {
	write!(f, "C call failed (invalid return {:?}): {}", self.0, &self.2)
    }
}

impl<'a, T> From<FFIError<'a, T>> for io::Error
{
    #[inline] 
    fn from(from: FFIError<'a, T>) -> Self
    {
	from.1
    }
}