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
17impl 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}