1use core::{
4 borrow::Borrow,
5 cmp,
6 ffi::CStr,
7 fmt, hash,
8 ops::{Deref, Index, RangeFull},
9};
10
11use munge::munge;
12use rancor::Fallible;
13
14use crate::{
15 primitive::FixedUsize, ser::Writer, ArchiveUnsized, Place, Portable,
16 RelPtr, SerializeUnsized,
17};
18
19#[derive(Portable)]
23#[rkyv(crate)]
24#[cfg_attr(
25 feature = "bytecheck",
26 derive(bytecheck::CheckBytes),
27 bytecheck(verify)
28)]
29#[repr(transparent)]
30pub struct ArchivedCString {
31 ptr: RelPtr<CStr>,
32}
33
34impl ArchivedCString {
35 #[inline]
42 pub fn as_bytes(&self) -> &[u8] {
43 self.as_c_str().to_bytes()
44 }
45
46 #[inline]
49 pub fn as_bytes_with_nul(&self) -> &[u8] {
50 self.as_c_str().to_bytes_with_nul()
51 }
52
53 #[inline]
55 pub fn as_c_str(&self) -> &CStr {
56 unsafe { &*self.ptr.as_ptr() }
57 }
58
59 #[inline]
61 pub fn resolve_from_c_str(
62 c_str: &CStr,
63 resolver: CStringResolver,
64 out: Place<Self>,
65 ) {
66 munge!(let ArchivedCString { ptr } = out);
67 RelPtr::emplace_unsized(
68 resolver.pos as usize,
69 c_str.archived_metadata(),
70 ptr,
71 );
72 }
73
74 pub fn serialize_from_c_str<S: Fallible + Writer + ?Sized>(
76 c_str: &CStr,
77 serializer: &mut S,
78 ) -> Result<CStringResolver, S::Error> {
79 Ok(CStringResolver {
80 pos: c_str.serialize_unsized(serializer)? as FixedUsize,
81 })
82 }
83}
84
85impl AsRef<CStr> for ArchivedCString {
86 fn as_ref(&self) -> &CStr {
87 self.as_c_str()
88 }
89}
90
91impl Borrow<CStr> for ArchivedCString {
92 #[inline]
93 fn borrow(&self) -> &CStr {
94 self.as_c_str()
95 }
96}
97
98impl fmt::Debug for ArchivedCString {
99 #[inline]
100 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101 self.as_c_str().fmt(f)
102 }
103}
104
105impl Deref for ArchivedCString {
106 type Target = CStr;
107
108 #[inline]
109 fn deref(&self) -> &Self::Target {
110 self.as_c_str()
111 }
112}
113
114impl Eq for ArchivedCString {}
115
116impl hash::Hash for ArchivedCString {
117 fn hash<H: hash::Hasher>(&self, state: &mut H) {
118 self.as_bytes_with_nul().hash(state);
119 }
120}
121
122impl Index<RangeFull> for ArchivedCString {
123 type Output = CStr;
124
125 #[inline]
126 fn index(&self, _: RangeFull) -> &Self::Output {
127 self.as_c_str()
128 }
129}
130
131impl Ord for ArchivedCString {
132 #[inline]
133 fn cmp(&self, other: &Self) -> cmp::Ordering {
134 self.as_bytes().cmp(other.as_bytes())
135 }
136}
137
138impl PartialEq for ArchivedCString {
139 #[inline]
140 fn eq(&self, other: &Self) -> bool {
141 self.as_bytes() == other.as_bytes()
142 }
143}
144
145impl PartialEq<&CStr> for ArchivedCString {
146 #[inline]
147 fn eq(&self, other: &&CStr) -> bool {
148 PartialEq::eq(self.as_c_str(), other)
149 }
150}
151
152impl PartialEq<ArchivedCString> for &CStr {
153 #[inline]
154 fn eq(&self, other: &ArchivedCString) -> bool {
155 PartialEq::eq(other.as_c_str(), self)
156 }
157}
158
159impl PartialOrd for ArchivedCString {
160 #[inline]
161 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
162 Some(self.cmp(other))
163 }
164}
165
166pub struct CStringResolver {
168 pos: FixedUsize,
169}
170
171#[cfg(feature = "bytecheck")]
172mod verify {
173 use core::ffi::CStr;
174
175 use bytecheck::{
176 rancor::{Fallible, Source},
177 CheckBytes, Verify,
178 };
179
180 use crate::{
181 ffi::ArchivedCString,
182 validation::{ArchiveContext, ArchiveContextExt},
183 };
184
185 unsafe impl<C> Verify<C> for ArchivedCString
186 where
187 C: Fallible + ArchiveContext + ?Sized,
188 C::Error: Source,
189 {
190 fn verify(&self, context: &mut C) -> Result<(), C::Error> {
191 let ptr = self.ptr.as_ptr_wrapping();
192 context.in_subtree(ptr, |context| unsafe {
193 CStr::check_bytes(ptr, context)
194 })
195 }
196 }
197}