rkyv/impls/alloc/
ffi.rs

1use core::ffi::CStr;
2
3use rancor::{Fallible, ResultExt, Source};
4
5use crate::{
6    alloc::{
7        alloc::{alloc, handle_alloc_error},
8        boxed::Box,
9        ffi::CString,
10    },
11    ffi::{ArchivedCString, CStringResolver},
12    ser::Writer,
13    traits::LayoutRaw,
14    Archive, Deserialize, DeserializeUnsized, Place, Serialize,
15};
16
17// CString
18
19impl Archive for CString {
20    type Archived = ArchivedCString;
21    type Resolver = CStringResolver;
22
23    #[inline]
24    fn resolve(&self, resolver: Self::Resolver, out: Place<Self::Archived>) {
25        ArchivedCString::resolve_from_c_str(self.as_c_str(), resolver, out);
26    }
27}
28
29impl<S: Fallible + Writer + ?Sized> Serialize<S> for CString {
30    fn serialize(
31        &self,
32        serializer: &mut S,
33    ) -> Result<Self::Resolver, S::Error> {
34        ArchivedCString::serialize_from_c_str(self.as_c_str(), serializer)
35    }
36}
37
38impl<D> Deserialize<CString, D> for ArchivedCString
39where
40    D: Fallible + ?Sized,
41    D::Error: Source,
42    CStr: DeserializeUnsized<CStr, D>,
43{
44    fn deserialize(&self, deserializer: &mut D) -> Result<CString, D::Error> {
45        let metadata = self.as_c_str().deserialize_metadata();
46        let layout = <CStr as LayoutRaw>::layout_raw(metadata).into_error()?;
47        let data_address = if layout.size() > 0 {
48            let ptr = unsafe { alloc(layout) };
49            if ptr.is_null() {
50                handle_alloc_error(layout);
51            }
52            ptr
53        } else {
54            crate::polyfill::dangling(&layout).as_ptr()
55        };
56        let out = ptr_meta::from_raw_parts_mut(data_address.cast(), metadata);
57        unsafe {
58            self.as_c_str().deserialize_unsized(deserializer, out)?;
59        }
60        let boxed = unsafe { Box::<CStr>::from_raw(out) };
61        Ok(CString::from(boxed))
62    }
63}
64
65impl PartialEq<CString> for ArchivedCString {
66    #[inline]
67    fn eq(&self, other: &CString) -> bool {
68        PartialEq::eq(self.as_c_str(), other.as_c_str())
69    }
70}
71
72impl PartialEq<ArchivedCString> for CString {
73    #[inline]
74    fn eq(&self, other: &ArchivedCString) -> bool {
75        PartialEq::eq(other.as_c_str(), self.as_c_str())
76    }
77}
78
79#[cfg(test)]
80mod tests {
81    use crate::{
82        alloc::{ffi::CString, string::String},
83        api::test::roundtrip,
84    };
85
86    #[test]
87    fn roundtrip_c_string() {
88        let value = unsafe {
89            CString::from_vec_unchecked(
90                String::from("hello world").into_bytes(),
91            )
92        };
93        roundtrip(&value);
94    }
95}