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)
}
}
};
}
pub(crate) use c_try;
#[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>
{
#[inline]
pub fn value(&self) -> &T
{
&self.0
}
#[inline]
pub fn to_value(&self) -> T
where T: Clone
{
self.0.clone()
}
#[inline]
pub fn into_value(self) -> T
{
self.0
}
#[inline]
pub fn into_parts(self) -> ((T, io::Error), impl fmt::Display + fmt::Debug + 'a)
{
((self.0, self.1), self.2)
}
#[inline]
pub fn error(&self) -> &io::Error
{
&self.1
}
#[inline]
pub fn message(&self) -> &(impl fmt::Display + fmt::Debug + 'a)
{
&self.2
}
pub fn into_message(self) -> impl fmt::Display + fmt::Debug + 'a
{
self.2
}
}
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
}
}