shared_bytes/
shared_str.rs

1#[cfg(test)]
2mod tests;
3
4use crate::{owned_slice::OwnedSlice, util::range, IndexOutOfBounds, RangeOfSubset, SharedBytes};
5use std::{
6    borrow::{Borrow, Cow},
7    fmt::{self, Debug, Display},
8    io,
9    net::ToSocketAddrs,
10    ops::{Deref, Range, RangeBounds},
11    sync::Arc,
12};
13
14#[derive(Clone)]
15pub struct SharedStr(pub(crate) Flavour);
16
17#[derive(Clone)]
18pub(crate) enum Flavour {
19    Static(&'static str),
20    ArcVecSlice(OwnedSlice<Arc<Vec<u8>>, str>),
21    ArcStringSlice(OwnedSlice<Arc<String>, str>),
22}
23
24impl SharedStr {
25    #[inline]
26    pub const fn new() -> Self {
27        Self(Flavour::Static(""))
28    }
29
30    #[inline]
31    pub const fn from_static(x: &'static str) -> Self {
32        Self(Flavour::Static(x))
33    }
34
35    #[inline]
36    pub fn from_string(x: String) -> Self {
37        Self::from_arc_string(Arc::new(x))
38    }
39
40    #[inline]
41    pub fn from_arc_string(x: Arc<String>) -> Self {
42        Self(Flavour::ArcStringSlice(OwnedSlice::new(x).unwrap()))
43    }
44
45    pub fn from_utf8(bytes: SharedBytes) -> Result<Self, SharedBytes> {
46        use crate::shared_bytes::Flavour::*;
47        let flavour = match bytes.0 {
48            Static(b) => match std::str::from_utf8(b) {
49                Ok(string) => Flavour::Static(string),
50                Err(_) => return Err(bytes),
51            },
52            ArcVecSlice(x) => Flavour::ArcVecSlice(
53                x.try_map_output()
54                    .map_err(|x| SharedBytes(ArcVecSlice(x)))?,
55            ),
56            ArcStringSlice(x) => Flavour::ArcStringSlice(
57                x.try_map_output()
58                    .map_err(|x| SharedBytes(ArcStringSlice(x)))?,
59            ),
60        };
61        Ok(Self(flavour))
62    }
63
64    pub fn into_string(self) -> String {
65        self.into_static_cow().into_owned()
66    }
67
68    fn into_static_cow(self) -> Cow<'static, str> {
69        match self.0 {
70            Flavour::Static(x) => Cow::Borrowed(x),
71            Flavour::ArcVecSlice(x) => Cow::Owned(
72                x.into_unwrapped(|vec| String::from_utf8(vec).unwrap(), ToOwned::to_owned),
73            ),
74            Flavour::ArcStringSlice(x) => {
75                Cow::Owned(x.into_unwrapped(Into::into, ToOwned::to_owned))
76            }
77        }
78    }
79
80    #[inline]
81    pub fn as_str(&self) -> &str {
82        self.as_slice()
83    }
84
85    #[inline]
86    pub fn as_slice(&self) -> &str {
87        match &self.0 {
88            Flavour::Static(x) => x,
89            Flavour::ArcVecSlice(x) => x,
90            Flavour::ArcStringSlice(x) => x,
91        }
92    }
93
94    pub fn as_static(&self) -> Option<&'static str> {
95        match &self.0 {
96            Flavour::Static(x) => Some(x),
97            _ => None,
98        }
99    }
100
101    pub fn len(&self) -> usize {
102        self.as_slice().len()
103    }
104
105    pub fn is_empty(&self) -> bool {
106        self.as_slice().is_empty()
107    }
108
109    pub fn clear(&mut self) {
110        *self = Self::new()
111    }
112
113    pub fn truncate(&mut self, at: usize) {
114        self.try_slice_mut(..at)
115            .unwrap_or_else(|_| panic!("truncate index '{at}' should be <= len '{}'", self.len()))
116    }
117
118    #[must_use = "consider fn truncate if you don't need the other half"]
119    pub fn split_off(&mut self, at: usize) -> Self {
120        self.try_split_off(at)
121            .unwrap_or_else(|| panic!("split index '{at}' should be <= len '{}'", self.len()))
122    }
123
124    // may be promoted to a pub fn in the future
125    fn try_split_off(&mut self, at: usize) -> Option<Self> {
126        self.as_slice().get(at..)?; // ensure `at` is not out of bounds
127        let mut split = self.clone();
128        split.slice_mut(at..);
129        self.slice_mut(..at);
130        Some(split)
131    }
132
133    pub fn range_of_subset(&self, subset: &str) -> Range<usize> {
134        RangeOfSubset::range_of_subset(self.as_slice(), subset)
135    }
136
137    pub fn slice_cloned<R: RangeBounds<usize>>(&self, r: R) -> Self {
138        self.non_generic_slice_cloned(self.slice_range_from_bounds(r))
139    }
140
141    fn non_generic_slice_cloned(&self, range: Range<usize>) -> Self {
142        self.non_generic_try_slice_cloned(range.clone())
143            .unwrap_or_else(|_| self.out_of_bounds_panic(range))
144    }
145
146    pub fn try_slice_cloned<R: RangeBounds<usize>>(&self, r: R) -> Result<Self, IndexOutOfBounds> {
147        self.non_generic_try_slice_cloned(self.slice_range_from_bounds(r))
148    }
149
150    fn non_generic_try_slice_cloned(&self, range: Range<usize>) -> Result<Self, IndexOutOfBounds> {
151        if self.as_slice().get(range.clone()).is_none() {
152            return Err(IndexOutOfBounds::new());
153        }
154        Ok(self.clone().slice_into(range))
155    }
156
157    pub fn slice_into<R: RangeBounds<usize>>(self, r: R) -> Self {
158        let range = self.slice_range_from_bounds(r);
159        self.non_generic_slice_into(range)
160    }
161
162    fn non_generic_slice_into(self, range: Range<usize>) -> Self {
163        self.non_generic_try_slice_into(range.clone())
164            .unwrap_or_else(|this| this.out_of_bounds_panic(range))
165    }
166
167    pub fn try_slice_into<R: RangeBounds<usize>>(self, r: R) -> Result<Self, Self> {
168        let range = self.slice_range_from_bounds(r);
169        self.non_generic_try_slice_into(range)
170    }
171
172    fn non_generic_try_slice_into(mut self, range: Range<usize>) -> Result<Self, Self> {
173        match self.internal_try_slice_mut(range) {
174            Ok(()) => Ok(self),
175            Err(()) => Err(self),
176        }
177    }
178
179    pub fn slice_mut<R: RangeBounds<usize>>(&mut self, r: R) {
180        self.non_generic_slice_mut(self.slice_range_from_bounds(r))
181    }
182
183    fn non_generic_slice_mut(&mut self, range: Range<usize>) {
184        self.internal_try_slice_mut(range.clone())
185            .unwrap_or_else(|()| self.out_of_bounds_panic(range))
186    }
187
188    pub fn try_slice_mut<R: RangeBounds<usize>>(&mut self, r: R) -> Result<(), IndexOutOfBounds> {
189        self.non_generic_try_slice_mut(self.slice_range_from_bounds(r))
190    }
191
192    fn non_generic_try_slice_mut(&mut self, range: Range<usize>) -> Result<(), IndexOutOfBounds> {
193        self.internal_try_slice_mut(range)
194            .map_err(|()| IndexOutOfBounds::new())
195    }
196
197    fn slice_range_from_bounds<R: RangeBounds<usize>>(&self, r: R) -> Range<usize> {
198        range::from_slice_bounds(r, || self.len())
199    }
200
201    fn out_of_bounds_panic<R: RangeBounds<usize> + Debug, T>(&self, range: R) -> T {
202        let length = self.len();
203        panic!("slice range {range:?} is out of bounds for length {length}")
204    }
205
206    #[must_use = "`internal_try_slice_mut` may fail to mutate `self`"]
207    fn internal_try_slice_mut(&mut self, range: Range<usize>) -> Result<(), ()> {
208        match &mut self.0 {
209            Flavour::Static(old) => match old.get(range) {
210                None => Err(()),
211                Some(new) => {
212                    *old = new;
213                    Ok(())
214                }
215            },
216            Flavour::ArcVecSlice(x) => x.try_slice_mut(range),
217            Flavour::ArcStringSlice(x) => x.try_slice_mut(range),
218        }
219    }
220}
221
222impl AsRef<[u8]> for SharedStr {
223    #[inline]
224    fn as_ref(&self) -> &[u8] {
225        self.as_slice().as_bytes()
226    }
227}
228
229impl AsRef<str> for SharedStr {
230    #[inline]
231    fn as_ref(&self) -> &str {
232        self.as_slice()
233    }
234}
235
236impl Borrow<str> for SharedStr {
237    #[inline]
238    fn borrow(&self) -> &str {
239        self.as_slice()
240    }
241}
242
243impl Debug for SharedStr {
244    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
245        Debug::fmt(self.as_str(), f)
246    }
247}
248
249impl Display for SharedStr {
250    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251        Display::fmt(self.as_str(), f)
252    }
253}
254
255impl Default for SharedStr {
256    #[inline]
257    fn default() -> Self {
258        Self::new()
259    }
260}
261
262impl Deref for SharedStr {
263    type Target = str;
264
265    #[inline]
266    fn deref(&self) -> &Self::Target {
267        self.as_slice()
268    }
269}
270
271impl Eq for SharedStr {}
272
273impl PartialEq for SharedStr {
274    #[inline]
275    fn eq(&self, other: &Self) -> bool {
276        self.as_slice() == other.as_slice()
277    }
278}
279
280impl<Other: ?Sized> PartialEq<&Other> for SharedStr
281where
282    Self: PartialEq<Other>,
283{
284    #[inline]
285    fn eq(&self, other: &&Other) -> bool {
286        self == *other
287    }
288}
289
290impl PartialEq<str> for SharedStr {
291    #[inline]
292    fn eq(&self, other: &str) -> bool {
293        self.as_slice() == other
294    }
295}
296
297impl PartialEq<String> for SharedStr {
298    #[inline]
299    fn eq(&self, other: &String) -> bool {
300        self.as_slice() == other.as_str()
301    }
302}
303
304impl std::hash::Hash for SharedStr {
305    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
306        self.as_slice().hash(state)
307    }
308}
309
310impl From<&'static str> for SharedStr {
311    #[inline]
312    fn from(x: &'static str) -> Self {
313        Self::from_static(x)
314    }
315}
316
317impl From<String> for SharedStr {
318    #[inline]
319    fn from(x: String) -> Self {
320        Self::from_string(x)
321    }
322}
323
324impl From<Arc<String>> for SharedStr {
325    #[inline]
326    fn from(x: Arc<String>) -> Self {
327        Self::from_arc_string(x)
328    }
329}
330
331impl From<char> for SharedStr {
332    #[inline]
333    fn from(x: char) -> Self {
334        Self::from_string(x.into())
335    }
336}
337
338impl From<SharedStr> for String {
339    fn from(x: SharedStr) -> Self {
340        x.into_string()
341    }
342}
343
344impl FromIterator<char> for SharedStr {
345    #[inline]
346    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
347        Self::from_string(iter.into_iter().collect())
348    }
349}
350
351impl<'a> FromIterator<&'a str> for SharedStr {
352    #[inline]
353    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
354        Self::from_string(iter.into_iter().collect())
355    }
356}
357
358impl FromIterator<String> for SharedStr {
359    #[inline]
360    fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
361        Self::from_string(iter.into_iter().collect())
362    }
363}
364
365impl ToSocketAddrs for SharedStr {
366    type Iter = <str as ToSocketAddrs>::Iter;
367
368    #[inline]
369    fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
370        self.as_str().to_socket_addrs()
371    }
372}