rkyv/impls/alloc/
ffi.rs

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