minfac 0.1.4

Lightweight Inversion Of Control
Documentation
use core::{marker::PhantomData, ops::Deref};

#[repr(C)]
#[derive(Clone, Copy)]
pub(crate) struct FfiStr<'a> {
    ptr: *const u8,
    len: usize,
    phantom: PhantomData<&'a ()>,
}

unsafe impl<'a> Send for FfiStr<'a> {}
unsafe impl<'a> Sync for FfiStr<'a> {}

impl<'a> core::fmt::Debug for FfiStr<'a> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        core::fmt::Debug::fmt(self.deref(), f)
    }
}
impl<'a> core::fmt::Display for FfiStr<'a> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        core::fmt::Display::fmt(self.deref(), f)
    }
}

impl<'a> From<&'a str> for FfiStr<'a> {
    fn from(value: &'a str) -> Self {
        let bytes = value.as_bytes();
        Self {
            ptr: bytes.as_ptr(),
            len: bytes.len(),
            phantom: PhantomData,
        }
    }
}

impl<'a> From<FfiStr<'a>> for &'a str {
    fn from(value: FfiStr<'a>) -> Self {
        unsafe {
            let bytes = core::slice::from_raw_parts(value.ptr, value.len);
            core::str::from_utf8_unchecked(bytes)
        }
    }
}

impl<'a> Deref for FfiStr<'a> {
    type Target = str;

    fn deref(&self) -> &Self::Target {
        (*self).into()
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn deref_through_str() {
        let x = "foobar";
        let ffi = FfiStr::from(x);
        assert_eq!(*ffi, *x);
    }
}