1pub mod repr;
4
5use crate::{Fallible, SerializeUnsized};
6use core::{
7 borrow::Borrow,
8 cmp, fmt, hash,
9 ops::{Deref, Index, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive},
10 pin::Pin,
11 str,
12};
13use repr::{ArchivedStringRepr, INLINE_CAPACITY};
14
15#[repr(transparent)]
21pub struct ArchivedString(repr::ArchivedStringRepr);
22
23impl ArchivedString {
24 #[inline]
26 pub fn as_str(&self) -> &str {
27 self.0.as_str()
28 }
29
30 #[inline]
32 pub fn pin_mut_str(self: Pin<&mut Self>) -> Pin<&mut str> {
33 unsafe { self.map_unchecked_mut(|s| s.0.as_mut_str()) }
34 }
35
36 #[inline]
43 pub unsafe fn resolve_from_str(
44 value: &str,
45 pos: usize,
46 resolver: StringResolver,
47 out: *mut Self,
48 ) {
49 if value.len() <= repr::INLINE_CAPACITY {
50 ArchivedStringRepr::emplace_inline(value, out.cast());
51 } else {
52 ArchivedStringRepr::emplace_out_of_line(value, pos, resolver.pos, out.cast());
53 }
54 }
55
56 #[inline]
58 pub fn serialize_from_str<S: Fallible + ?Sized>(
59 value: &str,
60 serializer: &mut S,
61 ) -> Result<StringResolver, S::Error>
62 where
63 str: SerializeUnsized<S>,
64 {
65 if value.len() <= INLINE_CAPACITY {
66 Ok(StringResolver { pos: 0 })
67 } else {
68 Ok(StringResolver {
69 pos: value.serialize_unsized(serializer)?,
70 })
71 }
72 }
73}
74
75impl AsRef<str> for ArchivedString {
76 #[inline]
77 fn as_ref(&self) -> &str {
78 self.as_str()
79 }
80}
81
82impl Borrow<str> for ArchivedString {
83 #[inline]
84 fn borrow(&self) -> &str {
85 self.as_str()
86 }
87}
88
89impl fmt::Debug for ArchivedString {
90 #[inline]
91 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
92 fmt::Debug::fmt(self.as_str(), f)
93 }
94}
95
96impl Deref for ArchivedString {
97 type Target = str;
98
99 #[inline]
100 fn deref(&self) -> &Self::Target {
101 self.as_str()
102 }
103}
104
105impl fmt::Display for ArchivedString {
106 #[inline]
107 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
108 fmt::Display::fmt(self.as_str(), f)
109 }
110}
111
112impl Eq for ArchivedString {}
113
114impl hash::Hash for ArchivedString {
115 #[inline]
116 fn hash<H: hash::Hasher>(&self, state: &mut H) {
117 self.as_str().hash(state)
118 }
119}
120
121macro_rules! impl_index {
122 ($index:ty) => {
123 impl Index<$index> for ArchivedString {
124 type Output = str;
125
126 #[inline]
127 fn index(&self, index: $index) -> &Self::Output {
128 self.as_str().index(index)
129 }
130 }
131 };
132}
133
134impl_index!(Range<usize>);
135impl_index!(RangeFrom<usize>);
136impl_index!(RangeFull);
137impl_index!(RangeInclusive<usize>);
138impl_index!(RangeTo<usize>);
139impl_index!(RangeToInclusive<usize>);
140
141impl Ord for ArchivedString {
142 #[inline]
143 fn cmp(&self, other: &Self) -> cmp::Ordering {
144 self.as_str().cmp(other.as_str())
145 }
146}
147
148impl PartialEq for ArchivedString {
149 #[inline]
150 fn eq(&self, other: &Self) -> bool {
151 self.as_str() == other.as_str()
152 }
153}
154
155impl PartialOrd for ArchivedString {
156 #[inline]
157 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
158 Some(self.cmp(other))
159 }
160}
161
162impl PartialEq<&str> for ArchivedString {
163 #[inline]
164 fn eq(&self, other: &&str) -> bool {
165 PartialEq::eq(self.as_str(), *other)
166 }
167}
168
169impl PartialEq<str> for ArchivedString {
170 #[inline]
171 fn eq(&self, other: &str) -> bool {
172 PartialEq::eq(self.as_str(), other)
173 }
174}
175
176impl PartialEq<ArchivedString> for &str {
177 #[inline]
178 fn eq(&self, other: &ArchivedString) -> bool {
179 PartialEq::eq(other.as_str(), *self)
180 }
181}
182
183impl PartialEq<ArchivedString> for str {
184 #[inline]
185 fn eq(&self, other: &ArchivedString) -> bool {
186 PartialEq::eq(other.as_str(), self)
187 }
188}
189
190impl PartialOrd<&str> for ArchivedString {
191 #[inline]
192 fn partial_cmp(&self, other: &&str) -> Option<cmp::Ordering> {
193 self.as_str().partial_cmp(*other)
194 }
195}
196
197impl PartialOrd<str> for ArchivedString {
198 #[inline]
199 fn partial_cmp(&self, other: &str) -> Option<cmp::Ordering> {
200 self.as_str().partial_cmp(other)
201 }
202}
203
204impl PartialOrd<ArchivedString> for &str {
205 #[inline]
206 fn partial_cmp(&self, other: &ArchivedString) -> Option<cmp::Ordering> {
207 self.partial_cmp(&other.as_str())
208 }
209}
210
211impl PartialOrd<ArchivedString> for str {
212 #[inline]
213 fn partial_cmp(&self, other: &ArchivedString) -> Option<cmp::Ordering> {
214 self.partial_cmp(other.as_str())
215 }
216}
217
218pub struct StringResolver {
220 pos: usize,
221}
222
223#[cfg(feature = "validation")]
224const _: () = {
225 use crate::validation::{owned::OwnedPointerError, ArchiveContext};
226 use bytecheck::{CheckBytes, Error};
227
228 impl<C: ArchiveContext + ?Sized> CheckBytes<C> for ArchivedString
229 where
230 C::Error: Error + 'static,
231 {
232 type Error = OwnedPointerError<
233 <ArchivedStringRepr as CheckBytes<C>>::Error,
234 <str as CheckBytes<C>>::Error,
235 C::Error,
236 >;
237
238 #[inline]
239 unsafe fn check_bytes<'a>(
240 value: *const Self,
241 context: &mut C,
242 ) -> Result<&'a Self, Self::Error> {
243 let repr = ArchivedStringRepr::check_bytes(value.cast(), context)
245 .map_err(OwnedPointerError::PointerCheckBytesError)?;
246
247 if repr.is_inline() {
248 str::check_bytes(repr.as_str_ptr(), context)
249 .map_err(OwnedPointerError::ValueCheckBytesError)?;
250 } else {
251 let base = value.cast();
252 let offset = repr.out_of_line_offset();
253 let metadata = repr.len();
254
255 let ptr = context
256 .check_subtree_ptr::<str>(base, offset, metadata)
257 .map_err(OwnedPointerError::ContextError)?;
258
259 let range = context
260 .push_prefix_subtree(ptr)
261 .map_err(OwnedPointerError::ContextError)?;
262 str::check_bytes(ptr, context).map_err(OwnedPointerError::ValueCheckBytesError)?;
263 context
264 .pop_prefix_range(range)
265 .map_err(OwnedPointerError::ContextError)?;
266 }
267
268 Ok(&*value)
269 }
270 }
271};