riot_wrappers/helpers.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
//! Small tools used in different wrappers without being actually public
/// Generalization of the Never type extracting workaround from
/// <https://github.com/rust-lang/rust/issues/43301#issuecomment-912390203> -- also useful to
/// extract return types of functions that (in what is compatible behavior in C) change their
/// return types.
///
/// With the introduction of ArgXType, it's actually not a ReturnType but AnyFunctionInvolvedType
/// extractor any more...
pub trait ReturnTypeExtractor {
type ReturnType;
type Arg1Type;
type Arg2Type;
}
impl<T> ReturnTypeExtractor for fn() -> T {
type ReturnType = T;
type Arg1Type = ();
type Arg2Type = ();
}
impl<T, I1> ReturnTypeExtractor for Option<unsafe extern "C" fn(I1) -> T> {
type ReturnType = T;
type Arg1Type = I1;
type Arg2Type = ();
}
impl<T, I1, I2> ReturnTypeExtractor for Option<unsafe extern "C" fn(I1, I2) -> T> {
type ReturnType = T;
type Arg1Type = I1;
type Arg2Type = I2;
}
/// Trait that eases conversions from a char pointer (no matter the signedness, they are used
/// inconsistently in RIOT) to a CStr. The result is often used with `?.to_str().ok()?`.
pub(crate) trait PointerToCStr {
/// Cast self around until it is suitable input to [`core::ffi::CStr::from_ptr()`], and run
/// that function. See there for safety requirements; in particular, the user needs to ensure
/// that the lifetime is suitable.
///
/// This returns None if self is the null pointer.
unsafe fn to_lifetimed_cstr<'a>(self) -> Option<&'a core::ffi::CStr>;
}
// Depending on the platform's default signeness of char, one of the casts is unnecessary.
impl PointerToCStr for *const u8 {
unsafe fn to_lifetimed_cstr<'a>(self) -> Option<&'a core::ffi::CStr> {
if self == core::ptr::null() {
None
} else {
Some(core::ffi::CStr::from_ptr(self as *const core::ffi::c_char))
}
}
}
impl PointerToCStr for *const i8 {
unsafe fn to_lifetimed_cstr<'a>(self) -> Option<&'a core::ffi::CStr> {
if self == core::ptr::null() {
None
} else {
Some(core::ffi::CStr::from_ptr(self as *const core::ffi::c_char))
}
}
}
// Gated because it is only used there -- expand as needed.
#[cfg(riot_module_vfs)]
mod slice_to_cstr {
/// Trait that eases conversions from a char slice (no matter the signedness, they are used
/// inconsistently in RIOT) to a CStr. The result is often used with `?.to_str().ok()?`.
pub(crate) trait SliceToCStr {
/// Cast self around until it is suitable input to [`core::ffi::CStr::from_bytes_until_nul()`],
/// and run that function.
///
/// Note that while "the slice until any null byte" could be safely used in Rust (as a slice or
/// even a str), its presence in C practically always indicates an error, also because that
/// data wouldn't be usable by other C code using its string conventions.
///
/// It is using a local error type because while the semantics of `from_bytes_until_nul` are
/// the right ones considering how this is used on C fields that are treated with `strlen()`
/// etc., that function is not stable yet and emulated.
fn to_cstr(&self) -> Result<&core::ffi::CStr, FromBytesUntilNulError>;
}
// Unlike in the from_ptr case, this is consistently taking u8, so only the i8 case gets casting.
impl SliceToCStr for [u8] {
fn to_cstr(&self) -> Result<&core::ffi::CStr, FromBytesUntilNulError> {
// Emulate from_bytes_until_null
let index = self
.iter()
.position(|&c| c == 0)
.ok_or(FromBytesUntilNulError {})?;
core::ffi::CStr::from_bytes_with_nul(&self[..index + 1])
// Actually the error is unreachable
.map_err(|_| FromBytesUntilNulError {})
}
}
impl SliceToCStr for [i8] {
fn to_cstr(&self) -> Result<&core::ffi::CStr, FromBytesUntilNulError> {
let s: &[u8] = unsafe { core::mem::transmute(self) };
s.to_cstr()
}
}
/// Error from [SliceToCStr::to_cstr].
///
/// This will become [core::ffi::c_str::FromBytesUntilNulError] once that's stable, and may be changed
/// without a breaking release even though it's technically a breaking change. (At this point, that
/// type will be `pub use`d here and deprecated).
#[derive(Debug)]
pub struct FromBytesUntilNulError {}
}
#[cfg(riot_module_vfs)]
pub use slice_to_cstr::*;