generic_str/
string_base.rs

1use core::cmp::Ordering;
2
3use generic_vec::{
4    raw::{Storage, StorageWithCapacity},
5    GenericVec,
6};
7
8#[cfg(feature = "alloc")]
9use generic_vec::HeapVec;
10#[cfg(feature = "alloc")]
11use std::{alloc::Allocator, borrow::Borrow};
12
13#[derive(Default, Copy, Clone)]
14#[repr(transparent)]
15pub struct StringBase<S: ?Sized> {
16    pub(crate) storage: S,
17}
18
19impl<S: StorageWithCapacity> StringBase<GenericVec<S::Item, S>> {
20    #[inline]
21    pub fn new_with_capacity(capacity: usize) -> Self {
22        Self::with_storage(S::with_capacity(capacity))
23    }
24}
25
26pub type OwnedString<T, S> = StringBase<GenericVec<T, S>>;
27pub type StringSlice<U> = StringBase<[U]>;
28
29impl<S: ?Sized + Storage> StringBase<GenericVec<S::Item, S>> {
30    /// Creates a new empty `String` with a particular storage backend.
31    ///
32    /// `String`s have an internal buffer to hold their data. The capacity is
33    /// the length of that buffer, and can be queried with the [`capacity`]
34    /// method. This method creates an empty `String`, but one with an initial
35    /// buffer that can hold `capacity` bytes. This is useful when you may be
36    /// appending a bunch of data to the `String`, reducing the number of
37    /// reallocations it needs to do.
38    ///
39    /// [`capacity`]: StringBase::capacity
40    ///
41    /// If the given capacity is `0`, no allocation will occur, and this method
42    /// is identical to the [`new`] method.
43    ///
44    /// [`new`]: StringBase::new
45    ///
46    /// # Examples
47    ///
48    /// Basic usage:
49    ///
50    /// ```
51    /// # use generic_str::String;
52    /// let mut s = String::with_capacity(10);
53    ///
54    /// // The String contains no chars, even though it has capacity for more
55    /// assert_eq!(s.len(), 0);
56    ///
57    /// // These are all done without reallocating...
58    /// let cap = s.capacity();
59    /// for _ in 0..10 {
60    ///     s.push('a');
61    /// }
62    ///
63    /// assert_eq!(s.capacity(), cap);
64    ///
65    /// // ...but this may make the string reallocate
66    /// s.push('a');
67    /// ```
68    #[inline]
69    pub fn with_storage(storage: S) -> Self
70    where
71        S: Sized,
72    {
73        StringBase {
74            storage: GenericVec::with_storage(storage),
75        }
76    }
77}
78
79impl<T: ?Sized + core::ops::Deref> core::ops::Deref for StringBase<T> {
80    type Target = StringBase<T::Target>;
81
82    fn deref(&self) -> &StringBase<T::Target> {
83        unsafe { core::mem::transmute::<&T::Target, &StringBase<T::Target>>(self.storage.deref()) }
84    }
85}
86
87impl<T: ?Sized + core::ops::DerefMut> core::ops::DerefMut for StringBase<T> {
88    fn deref_mut(&mut self) -> &mut StringBase<T::Target> {
89        unsafe {
90            core::mem::transmute::<&mut T::Target, &mut StringBase<T::Target>>(
91                self.storage.deref_mut(),
92            )
93        }
94    }
95}
96
97impl<T: ?Sized + AsRef<U>, U: ?Sized> AsRef<StringBase<U>> for StringBase<T> {
98    fn as_ref(&self) -> &StringBase<U> {
99        unsafe { core::mem::transmute::<&U, &StringBase<U>>(self.storage.as_ref()) }
100    }
101}
102
103impl<T: ?Sized + AsMut<U>, U: ?Sized> AsMut<StringBase<U>> for StringBase<T> {
104    fn as_mut(&mut self) -> &mut StringBase<U> {
105        unsafe { core::mem::transmute::<&mut U, &mut StringBase<U>>(self.storage.as_mut()) }
106    }
107}
108
109#[cfg(feature = "alloc")]
110impl<T, A: Allocator> Borrow<StringBase<[T]>> for StringBase<HeapVec<T, A>> {
111    fn borrow(&self) -> &StringBase<[T]> {
112        unsafe { std::mem::transmute::<&[T], &StringBase<[T]>>(self.storage.borrow()) }
113    }
114}
115
116#[cfg(feature = "alloc")]
117impl<T: Clone> ToOwned for StringBase<[T]> {
118    type Owned = StringBase<HeapVec<T>>;
119
120    fn to_owned(&self) -> Self::Owned {
121        Self::Owned {
122            storage: self.storage.to_owned().into(),
123        }
124    }
125}
126
127impl<S: ?Sized + Storage, T: ?Sized + Storage> PartialEq<OwnedString<T::Item, T>>
128    for StringBase<GenericVec<S::Item, S>>
129where
130    GenericVec<S::Item, S>: PartialEq<GenericVec<T::Item, T>>,
131{
132    fn eq(&self, other: &OwnedString<T::Item, T>) -> bool {
133        self.storage.eq(&other.storage)
134    }
135}
136
137impl<S: ?Sized + Storage> PartialEq<OwnedString<S::Item, S>> for StringSlice<S::Item>
138where
139    S::Item: PartialEq,
140{
141    fn eq(&self, other: &OwnedString<S::Item, S>) -> bool {
142        other.storage.eq(&self.storage)
143    }
144}
145
146impl<S: ?Sized + Storage> PartialEq<OwnedString<S::Item, S>> for &StringSlice<S::Item>
147where
148    S::Item: PartialEq,
149{
150    fn eq(&self, other: &OwnedString<S::Item, S>) -> bool {
151        other.storage.eq(&self.storage)
152    }
153}
154
155impl<S: ?Sized + Storage> PartialEq<StringSlice<S::Item>> for OwnedString<S::Item, S>
156where
157    S::Item: PartialEq,
158{
159    fn eq(&self, other: &StringSlice<S::Item>) -> bool {
160        self.storage.eq(&other.storage)
161    }
162}
163
164impl<S: ?Sized + Storage> PartialEq<&StringSlice<S::Item>> for OwnedString<S::Item, S>
165where
166    S::Item: PartialEq,
167{
168    fn eq(&self, other: &&StringSlice<S::Item>) -> bool {
169        self.storage.eq(&other.storage)
170    }
171}
172
173impl<U: PartialEq> PartialEq<StringSlice<U>> for StringSlice<U> {
174    fn eq(&self, other: &StringSlice<U>) -> bool {
175        self.storage.eq(&other.storage)
176    }
177}
178
179impl<S: ?Sized + Storage> Eq for OwnedString<S::Item, S> where S::Item: Eq {}
180impl<U: Eq> Eq for StringSlice<U> {}
181
182impl<S: ?Sized + Storage, T: ?Sized + Storage> PartialOrd<OwnedString<T::Item, T>>
183    for OwnedString<S::Item, S>
184where
185    GenericVec<S::Item, S>: PartialOrd<GenericVec<T::Item, T>>,
186{
187    fn partial_cmp(&self, other: &OwnedString<T::Item, T>) -> Option<Ordering> {
188        self.storage.partial_cmp(&other.storage)
189    }
190}
191
192impl<S: ?Sized + Storage> PartialOrd<OwnedString<S::Item, S>> for StringSlice<S::Item>
193where
194    S::Item: PartialOrd,
195{
196    fn partial_cmp(&self, other: &OwnedString<S::Item, S>) -> Option<Ordering> {
197        other.storage.partial_cmp(&self.storage)
198    }
199}
200
201impl<S: ?Sized + Storage> PartialOrd<OwnedString<S::Item, S>> for &StringSlice<S::Item>
202where
203    S::Item: PartialOrd,
204{
205    fn partial_cmp(&self, other: &OwnedString<S::Item, S>) -> Option<Ordering> {
206        other.storage.partial_cmp(&self.storage)
207    }
208}
209
210impl<S: ?Sized + Storage> PartialOrd<StringSlice<S::Item>> for OwnedString<S::Item, S>
211where
212    S::Item: PartialOrd,
213{
214    fn partial_cmp(&self, other: &StringSlice<S::Item>) -> Option<Ordering> {
215        self.storage.partial_cmp(&other.storage)
216    }
217}
218
219impl<S: ?Sized + Storage> PartialOrd<&StringSlice<S::Item>> for OwnedString<S::Item, S>
220where
221    S::Item: PartialOrd,
222{
223    fn partial_cmp(&self, other: &&StringSlice<S::Item>) -> Option<Ordering> {
224        self.storage.partial_cmp(&other.storage)
225    }
226}
227
228impl<U: PartialOrd> PartialOrd<StringSlice<U>> for StringSlice<U> {
229    fn partial_cmp(&self, other: &StringSlice<U>) -> Option<Ordering> {
230        self.storage.partial_cmp(&other.storage)
231    }
232}
233
234impl<S: ?Sized + Storage> Ord for OwnedString<S::Item, S>
235where
236    S::Item: Ord,
237{
238    fn cmp(&self, other: &Self) -> Ordering {
239        self.storage.cmp(&other.storage)
240    }
241}
242impl<U: Ord> Ord for StringSlice<U> {
243    fn cmp(&self, other: &Self) -> Ordering {
244        self.storage.cmp(&other.storage)
245    }
246}