1use crate::{ser::Serializer, ArchiveUnsized, MetadataResolver, RelPtr, SerializeUnsized};
4use core::{
5 borrow::Borrow,
6 cmp, fmt, hash,
7 ops::{Deref, Index, RangeFull},
8 pin::Pin,
9};
10use std::ffi::CStr;
11
12#[repr(transparent)]
16pub struct ArchivedCString(RelPtr<CStr>);
17
18impl ArchivedCString {
19 #[inline]
25 pub fn as_bytes(&self) -> &[u8] {
26 self.as_c_str().to_bytes()
27 }
28
29 #[inline]
32 pub fn as_bytes_with_nul(&self) -> &[u8] {
33 self.as_c_str().to_bytes_with_nul()
34 }
35
36 #[inline]
38 pub fn as_c_str(&self) -> &CStr {
39 unsafe { &*self.0.as_ptr() }
40 }
41
42 #[inline]
44 pub fn pin_mut_c_str(self: Pin<&mut Self>) -> Pin<&mut CStr> {
45 unsafe { self.map_unchecked_mut(|s| &mut *s.0.as_mut_ptr()) }
46 }
47
48 #[inline]
55 pub unsafe fn resolve_from_c_str(
56 c_str: &CStr,
57 pos: usize,
58 resolver: CStringResolver,
59 out: *mut Self,
60 ) {
61 let (fp, fo) = out_field!(out.0);
62 #[allow(clippy::unit_arg)]
64 c_str.resolve_unsized(pos + fp, resolver.pos, resolver.metadata_resolver, fo);
65 }
66
67 #[inline]
69 pub fn serialize_from_c_str<S: Serializer + ?Sized>(
70 c_str: &CStr,
71 serializer: &mut S,
72 ) -> Result<CStringResolver, S::Error> {
73 Ok(CStringResolver {
74 pos: c_str.serialize_unsized(serializer)?,
75 metadata_resolver: c_str.serialize_metadata(serializer)?,
76 })
77 }
78}
79
80impl AsRef<CStr> for ArchivedCString {
81 fn as_ref(&self) -> &CStr {
82 self.as_c_str()
83 }
84}
85
86impl Borrow<CStr> for ArchivedCString {
87 #[inline]
88 fn borrow(&self) -> &CStr {
89 self.as_c_str()
90 }
91}
92
93impl fmt::Debug for ArchivedCString {
94 #[inline]
95 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96 self.as_c_str().fmt(f)
97 }
98}
99
100impl Deref for ArchivedCString {
101 type Target = CStr;
102
103 #[inline]
104 fn deref(&self) -> &Self::Target {
105 self.as_c_str()
106 }
107}
108
109impl Eq for ArchivedCString {}
110
111impl hash::Hash for ArchivedCString {
112 #[inline]
113 fn hash<H: hash::Hasher>(&self, state: &mut H) {
114 self.as_bytes_with_nul().hash(state);
115 }
116}
117
118impl Index<RangeFull> for ArchivedCString {
119 type Output = CStr;
120
121 #[inline]
122 fn index(&self, _: RangeFull) -> &Self::Output {
123 self.as_c_str()
124 }
125}
126
127impl Ord for ArchivedCString {
128 #[inline]
129 fn cmp(&self, other: &Self) -> cmp::Ordering {
130 self.as_bytes().cmp(other.as_bytes())
131 }
132}
133
134impl PartialEq for ArchivedCString {
135 #[inline]
136 fn eq(&self, other: &Self) -> bool {
137 self.as_bytes() == other.as_bytes()
138 }
139}
140
141impl PartialEq<&CStr> for ArchivedCString {
142 #[inline]
143 fn eq(&self, other: &&CStr) -> bool {
144 PartialEq::eq(self.as_c_str(), other)
145 }
146}
147
148impl PartialEq<ArchivedCString> for &CStr {
149 #[inline]
150 fn eq(&self, other: &ArchivedCString) -> bool {
151 PartialEq::eq(other.as_c_str(), self)
152 }
153}
154
155impl PartialOrd for ArchivedCString {
156 #[inline]
157 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
158 Some(self.cmp(other))
159 }
160}
161
162pub struct CStringResolver {
164 pos: usize,
165 metadata_resolver: MetadataResolver<CStr>,
166}
167
168#[cfg(feature = "validation")]
169const _: () = {
170 use crate::validation::{
171 owned::{CheckOwnedPointerError, OwnedPointerError},
172 ArchiveContext,
173 };
174 use bytecheck::{CheckBytes, Error};
175
176 impl<C: ArchiveContext + ?Sized> CheckBytes<C> for ArchivedCString
177 where
178 C::Error: Error,
179 {
180 type Error = CheckOwnedPointerError<CStr, C>;
181
182 #[inline]
183 unsafe fn check_bytes<'a>(
184 value: *const Self,
185 context: &mut C,
186 ) -> Result<&'a Self, Self::Error> {
187 let rel_ptr = RelPtr::<CStr>::manual_check_bytes(value.cast(), context)
188 .map_err(OwnedPointerError::PointerCheckBytesError)?;
189 let ptr = context
190 .check_subtree_rel_ptr(rel_ptr)
191 .map_err(OwnedPointerError::ContextError)?;
192
193 let range = context
194 .push_prefix_subtree(ptr)
195 .map_err(OwnedPointerError::ContextError)?;
196 CStr::check_bytes(ptr, context).map_err(OwnedPointerError::ValueCheckBytesError)?;
197 context
198 .pop_prefix_range(range)
199 .map_err(OwnedPointerError::ContextError)?;
200
201 Ok(&*value)
202 }
203 }
204};