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 self.as_str().partial_cmp(other.as_str())
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
183pub struct StringResolver {
185 pos: usize,
186}
187
188#[cfg(feature = "validation")]
189const _: () = {
190 use crate::validation::{
191 owned::{CheckOwnedPointerError, OwnedPointerError},
192 ArchiveContext,
193 };
194 use bytecheck::{CheckBytes, Error};
195
196 impl<C: ArchiveContext + ?Sized> CheckBytes<C> for ArchivedString
197 where
198 C::Error: Error,
199 {
200 type Error = CheckOwnedPointerError<str, C>;
201
202 #[inline]
203 unsafe fn check_bytes<'a>(
204 value: *const Self,
205 context: &mut C,
206 ) -> Result<&'a Self, Self::Error> {
207 let repr = &*value.cast::<ArchivedStringRepr>();
209
210 if repr.is_inline() {
211 str::check_bytes(repr.as_str_ptr(), context)
212 .map_err(OwnedPointerError::ValueCheckBytesError)?;
213 } else {
214 let base = value.cast();
215 let offset = repr.out_of_line_offset();
216 let metadata = repr.len();
217
218 let ptr = context
219 .check_subtree_ptr::<str>(base, offset, metadata)
220 .map_err(OwnedPointerError::ContextError)?;
221
222 let range = context
223 .push_prefix_subtree(ptr)
224 .map_err(OwnedPointerError::ContextError)?;
225 str::check_bytes(ptr, context).map_err(OwnedPointerError::ValueCheckBytesError)?;
226 context
227 .pop_prefix_range(range)
228 .map_err(OwnedPointerError::ContextError)?;
229 }
230
231 Ok(&*value)
232 }
233 }
234};