rkyv_test/string/
mod.rs

1//! Archived versions of string types.
2
3pub 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/// An archived [`String`].
16///
17/// This has inline and out-of-line representations. Short strings will use the available space
18/// inside the structure to store the string, and long strings will store a
19/// [`RelPtr`](crate::RelPtr) to a `str` instead.
20#[repr(transparent)]
21pub struct ArchivedString(repr::ArchivedStringRepr);
22
23impl ArchivedString {
24    /// Extracts a string slice containing the entire `ArchivedString`.
25    #[inline]
26    pub fn as_str(&self) -> &str {
27        self.0.as_str()
28    }
29
30    /// Extracts a pinned mutable string slice containing the entire `ArchivedString`.
31    #[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    /// Resolves an archived string from a given `str`.
37    ///
38    /// # Safety
39    ///
40    /// - `pos` must be the position of `out` within the archive
41    /// - `resolver` must be the result of serializing `value`
42    #[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    /// Serializes an archived string from a given `str`.
57    #[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
183/// The resolver for `String`.
184pub 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            // The repr is always valid
208            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};