stabby_abi/alloc/
string.rs

1use super::{
2    boxed::BoxedSlice,
3    sync::{ArcSlice, WeakSlice},
4    vec::Vec,
5    AllocationError, IAlloc,
6};
7use core::hash::Hash;
8
9/// A growable owned string.
10#[crate::stabby]
11#[derive(Clone)]
12pub struct String<Alloc: IAlloc = super::DefaultAllocator> {
13    pub(crate) inner: Vec<u8, Alloc>,
14}
15
16#[cfg(not(stabby_default_alloc = "disabled"))]
17impl String {
18    /// Constructs a new string using the default allocator.
19    pub const fn new() -> Self {
20        Self { inner: Vec::new() }
21    }
22}
23impl<Alloc: IAlloc> String<Alloc> {
24    /// Constructs a new string using the provided allocator.
25    pub const fn new_in(alloc: Alloc) -> Self {
26        Self {
27            inner: Vec::new_in(alloc),
28        }
29    }
30    /// Returns self as a borrowed string
31    pub fn as_str(&self) -> &str {
32        unsafe { core::str::from_utf8_unchecked(self.inner.as_slice()) }
33    }
34    /// Returns self as a mutably borrowed string
35    pub fn as_str_mut(&mut self) -> &mut str {
36        unsafe { core::str::from_utf8_unchecked_mut(self.inner.as_slice_mut()) }
37    }
38    fn try_concat_str(&mut self, s: &str) -> Result<(), AllocationError> {
39        self.inner.try_copy_extend(s.as_bytes())
40    }
41    /// Attempts to concatenate `s` to `self`
42    /// # Errors
43    /// This returns an [`AllocationError`] if reallocation was needed and failed to concatenate.
44    pub fn try_concat<S: AsRef<str> + ?Sized>(&mut self, s: &S) -> Result<(), AllocationError> {
45        self.try_concat_str(s.as_ref())
46    }
47}
48impl<Alloc: IAlloc + Default> Default for String<Alloc> {
49    fn default() -> Self {
50        Self {
51            inner: Vec::default(),
52        }
53    }
54}
55impl<S: AsRef<str> + ?Sized, Alloc: IAlloc> core::ops::Add<&S> for String<Alloc> {
56    type Output = Self;
57    fn add(mut self, rhs: &S) -> Self::Output {
58        self += rhs.as_ref();
59        self
60    }
61}
62impl<S: AsRef<str> + ?Sized, Alloc: IAlloc> core::ops::AddAssign<&S> for String<Alloc> {
63    fn add_assign(&mut self, rhs: &S) {
64        self.inner.copy_extend(rhs.as_ref().as_bytes())
65    }
66}
67
68impl<Alloc: IAlloc> From<String<Alloc>> for Vec<u8, Alloc> {
69    fn from(value: String<Alloc>) -> Self {
70        value.inner
71    }
72}
73
74impl<Alloc: IAlloc> TryFrom<Vec<u8, Alloc>> for String<Alloc> {
75    type Error = core::str::Utf8Error;
76    fn try_from(value: Vec<u8, Alloc>) -> Result<Self, Self::Error> {
77        core::str::from_utf8(value.as_slice())?;
78        Ok(Self { inner: value })
79    }
80}
81
82impl<Alloc: IAlloc> core::ops::Deref for String<Alloc> {
83    type Target = str;
84    fn deref(&self) -> &Self::Target {
85        self.as_str()
86    }
87}
88
89impl<Alloc: IAlloc> core::convert::AsRef<str> for String<Alloc> {
90    fn as_ref(&self) -> &str {
91        self.as_str()
92    }
93}
94impl<Alloc: IAlloc> core::ops::DerefMut for String<Alloc> {
95    fn deref_mut(&mut self) -> &mut Self::Target {
96        self.as_str_mut()
97    }
98}
99
100impl<Alloc: IAlloc> core::fmt::Debug for String<Alloc> {
101    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
102        core::fmt::Debug::fmt(self.as_str(), f)
103    }
104}
105impl<Alloc: IAlloc> core::fmt::Display for String<Alloc> {
106    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
107        core::fmt::Display::fmt(self.as_str(), f)
108    }
109}
110impl<Alloc: IAlloc> Hash for String<Alloc> {
111    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
112        self.as_str().hash(state)
113    }
114}
115impl<Alloc: IAlloc, Rhs: AsRef<str>> PartialEq<Rhs> for String<Alloc> {
116    fn eq(&self, other: &Rhs) -> bool {
117        self.as_str() == other.as_ref()
118    }
119}
120impl<Alloc: IAlloc> Eq for String<Alloc> {}
121impl<Alloc: IAlloc, Rhs: AsRef<str>> PartialOrd<Rhs> for String<Alloc> {
122    fn partial_cmp(&self, other: &Rhs) -> Option<core::cmp::Ordering> {
123        self.as_str().partial_cmp(other.as_ref())
124    }
125}
126impl<Alloc: IAlloc> Ord for String<Alloc> {
127    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
128        self.as_str().cmp(other.as_str())
129    }
130}
131
132impl<Alloc: IAlloc + Default> From<&str> for String<Alloc> {
133    fn from(value: &str) -> Self {
134        Self::default() + value
135    }
136}
137
138impl<Alloc: IAlloc + Default> From<crate::str::Str<'_>> for String<Alloc> {
139    fn from(value: crate::str::Str<'_>) -> Self {
140        Self::default() + value.as_ref()
141    }
142}
143
144/// A reference counted boxed string.
145#[crate::stabby]
146pub struct ArcStr<Alloc: IAlloc = super::DefaultAllocator> {
147    inner: ArcSlice<u8, Alloc>,
148}
149impl<Alloc: IAlloc> ArcStr<Alloc> {
150    /// Returns a borrow to the inner string.
151    pub fn as_str(&self) -> &str {
152        unsafe { core::str::from_utf8_unchecked(self.inner.as_slice()) }
153    }
154    /// Returns a mutably borrow to the inner str.
155    /// # Safety
156    /// [`Self::is_unique`] must be true.
157    pub unsafe fn as_str_mut_unchecked(&mut self) -> &mut str {
158        unsafe { core::str::from_utf8_unchecked_mut(self.inner.as_slice_mut_unchecked()) }
159    }
160    /// Returns a mutably borrow to the inner str if no other borrows of it can exist.
161    pub fn as_str_mut(&mut self) -> Option<&mut str> {
162        Self::is_unique(self).then(|| unsafe { self.as_str_mut_unchecked() })
163    }
164    /// Whether or not `this` is the sole owner of its data, including weak owners.
165    pub fn is_unique(this: &Self) -> bool {
166        ArcSlice::is_unique(&this.inner)
167    }
168}
169impl<Alloc: IAlloc> AsRef<str> for ArcStr<Alloc> {
170    fn as_ref(&self) -> &str {
171        self.as_str()
172    }
173}
174
175impl<Alloc: IAlloc> core::fmt::Debug for ArcStr<Alloc> {
176    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
177        core::fmt::Debug::fmt(self.as_str(), f)
178    }
179}
180impl<Alloc: IAlloc> core::fmt::Display for ArcStr<Alloc> {
181    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
182        core::fmt::Display::fmt(self.as_str(), f)
183    }
184}
185impl<Alloc: IAlloc> core::ops::Deref for ArcStr<Alloc> {
186    type Target = str;
187    fn deref(&self) -> &Self::Target {
188        self.as_str()
189    }
190}
191impl<Alloc: IAlloc> From<String<Alloc>> for ArcStr<Alloc> {
192    fn from(value: String<Alloc>) -> Self {
193        Self {
194            inner: value.inner.into(),
195        }
196    }
197}
198impl<Alloc: IAlloc> TryFrom<ArcStr<Alloc>> for String<Alloc> {
199    type Error = ArcStr<Alloc>;
200    fn try_from(value: ArcStr<Alloc>) -> Result<Self, ArcStr<Alloc>> {
201        match value.inner.try_into() {
202            Ok(vec) => Ok(String { inner: vec }),
203            Err(slice) => Err(ArcStr { inner: slice }),
204        }
205    }
206}
207impl<Alloc: IAlloc> Clone for ArcStr<Alloc> {
208    fn clone(&self) -> Self {
209        Self {
210            inner: self.inner.clone(),
211        }
212    }
213}
214impl<Alloc: IAlloc> Eq for ArcStr<Alloc> {}
215impl<Alloc: IAlloc> PartialEq for ArcStr<Alloc> {
216    fn eq(&self, other: &Self) -> bool {
217        self.as_str() == other.as_str()
218    }
219}
220impl<Alloc: IAlloc> Ord for ArcStr<Alloc> {
221    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
222        self.as_str().cmp(other.as_str())
223    }
224}
225impl<Alloc: IAlloc> PartialOrd for ArcStr<Alloc> {
226    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
227        Some(self.cmp(other))
228    }
229}
230impl<Alloc: IAlloc> Hash for ArcStr<Alloc> {
231    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
232        self.as_str().hash(state)
233    }
234}
235
236/// A weak reference counted boxed string.
237#[crate::stabby]
238pub struct WeakStr<Alloc: IAlloc = super::DefaultAllocator> {
239    inner: WeakSlice<u8, Alloc>,
240}
241impl<Alloc: IAlloc> WeakStr<Alloc> {
242    /// Returns a strong reference if the strong count hasn't reached 0 yet.
243    pub fn upgrade(&self) -> Option<ArcStr<Alloc>> {
244        self.inner.upgrade().map(|inner| ArcStr { inner })
245    }
246    /// Returns a strong reference to the string.
247    ///
248    /// If you're using this, there are probably design issues in your program...
249    pub fn force_upgrade(&self) -> ArcStr<Alloc> {
250        ArcStr {
251            inner: self.inner.force_upgrade(),
252        }
253    }
254}
255impl<Alloc: IAlloc> From<&ArcStr<Alloc>> for WeakStr<Alloc> {
256    fn from(value: &ArcStr<Alloc>) -> Self {
257        Self {
258            inner: (&value.inner).into(),
259        }
260    }
261}
262impl<Alloc: IAlloc> Clone for WeakStr<Alloc> {
263    fn clone(&self) -> Self {
264        Self {
265            inner: self.inner.clone(),
266        }
267    }
268}
269
270/// A boxed string.
271#[crate::stabby]
272pub struct BoxedStr<Alloc: IAlloc = super::DefaultAllocator> {
273    inner: BoxedSlice<u8, Alloc>,
274}
275impl<Alloc: IAlloc> BoxedStr<Alloc> {
276    /// Returns a borrow to the inner string.
277    pub fn as_str(&self) -> &str {
278        unsafe { core::str::from_utf8_unchecked(self.inner.as_slice()) }
279    }
280    /// Returns a mutable borrow to the inner string.
281    pub fn as_str_mut(&mut self) -> &mut str {
282        unsafe { core::str::from_utf8_unchecked_mut(self.inner.as_slice_mut()) }
283    }
284}
285impl<Alloc: IAlloc> AsRef<str> for BoxedStr<Alloc> {
286    fn as_ref(&self) -> &str {
287        self.as_str()
288    }
289}
290impl<Alloc: IAlloc> core::ops::Deref for BoxedStr<Alloc> {
291    type Target = str;
292    fn deref(&self) -> &Self::Target {
293        self.as_str()
294    }
295}
296impl<Alloc: IAlloc> From<String<Alloc>> for BoxedStr<Alloc> {
297    fn from(value: String<Alloc>) -> Self {
298        Self {
299            inner: value.inner.into(),
300        }
301    }
302}
303impl<Alloc: IAlloc> From<BoxedStr<Alloc>> for String<Alloc> {
304    fn from(value: BoxedStr<Alloc>) -> Self {
305        String {
306            inner: value.inner.into(),
307        }
308    }
309}
310impl<Alloc: IAlloc> Eq for BoxedStr<Alloc> {}
311impl<Alloc: IAlloc> PartialEq for BoxedStr<Alloc> {
312    fn eq(&self, other: &Self) -> bool {
313        self.as_str() == other.as_str()
314    }
315}
316impl<Alloc: IAlloc> Ord for BoxedStr<Alloc> {
317    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
318        self.as_str().cmp(other.as_str())
319    }
320}
321impl<Alloc: IAlloc> PartialOrd for BoxedStr<Alloc> {
322    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
323        Some(self.cmp(other))
324    }
325}
326impl<Alloc: IAlloc> core::hash::Hash for BoxedStr<Alloc> {
327    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
328        self.as_str().hash(state)
329    }
330}
331
332impl<Alloc: IAlloc> core::fmt::Debug for BoxedStr<Alloc> {
333    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
334        core::fmt::Debug::fmt(self.as_str(), f)
335    }
336}
337impl<Alloc: IAlloc> core::fmt::Display for BoxedStr<Alloc> {
338    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
339        core::fmt::Display::fmt(self.as_str(), f)
340    }
341}
342
343impl core::fmt::Write for String {
344    fn write_str(&mut self, s: &str) -> core::fmt::Result {
345        self.try_concat(s).map_err(|_| core::fmt::Error)
346    }
347}
348
349#[cfg(feature = "std")]
350mod std_impl {
351    use crate::alloc::IAlloc;
352    impl<Alloc: IAlloc + Default> From<std::string::String> for crate::alloc::string::String<Alloc> {
353        fn from(value: std::string::String) -> Self {
354            Self::from(value.as_ref())
355        }
356    }
357    impl<Alloc: IAlloc + Default> From<crate::alloc::string::String<Alloc>> for std::string::String {
358        fn from(value: crate::alloc::string::String<Alloc>) -> Self {
359            Self::from(value.as_ref())
360        }
361    }
362}
363
364#[cfg(feature = "serde")]
365mod serde_impl {
366    use super::*;
367    use crate::alloc::IAlloc;
368    use serde::{Deserialize, Serialize};
369    impl<Alloc: IAlloc> Serialize for String<Alloc> {
370        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
371        where
372            S: serde::Serializer,
373        {
374            let slice: &str = self;
375            slice.serialize(serializer)
376        }
377    }
378    impl<'a, Alloc: IAlloc + Default> Deserialize<'a> for String<Alloc> {
379        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
380        where
381            D: serde::Deserializer<'a>,
382        {
383            crate::str::Str::deserialize(deserializer).map(Into::into)
384        }
385    }
386}