cffi 0.1.7

Safe* C FFI interface generation
Documentation
use std::error::Error;
use std::marker::PhantomData;

use super::null_ptr_error;
use super::{FromForeign, InputType, ReturnType, Slice, ToForeign};

pub struct StrMarshaler<'a>(&'a PhantomData<()>);

impl InputType for StrMarshaler<'_> {
    type Foreign = Slice<u8>;
    type ForeignTraitObject = ();
}

impl ReturnType for StrMarshaler<'_> {
    type Foreign = Slice<u8>;
    type ForeignTraitObject = ();

    #[inline(always)]
    fn foreign_default() -> Self::Foreign {
        Slice::default()
    }
}

impl<'a> ToForeign<&'a str, Slice<u8>> for StrMarshaler<'a> {
    type Error = Box<dyn Error>;

    #[inline(always)]
    fn to_foreign(input: &'a str) -> Result<Slice<u8>, Self::Error> {
        let bytes = input.to_owned().into_boxed_str().into_boxed_bytes();
        let len = bytes.len();

        Ok(Slice {
            data: Box::into_raw(bytes) as _,
            len,
        })
    }
}

impl<'a> FromForeign<Slice<u8>, &'a str> for StrMarshaler<'a> {
    type Error = Box<dyn Error>;

    #[inline(always)]
    unsafe fn from_foreign(slice: Slice<u8>) -> Result<&'a str, Self::Error> {
        if slice.data.is_null() {
            return Err(null_ptr_error());
        }

        let r = std::slice::from_raw_parts(slice.data as _, slice.len);
        std::str::from_utf8(r).map_err(|e| Box::new(e) as _)
    }
}

impl<'a> FromForeign<Slice<u8>, Option<&'a str>> for StrMarshaler<'a> {
    type Error = Box<dyn Error>;

    #[inline(always)]
    unsafe fn from_foreign(slice: Slice<u8>) -> Result<Option<&'a str>, Self::Error> {
        if slice.data.is_null() {
            return Ok(None);
        }

        let r = std::slice::from_raw_parts(slice.data as _, slice.len);
        std::str::from_utf8(r)
            .map(Some)
            .map_err(|e| Box::new(e) as _)
    }
}