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