1use super::{
2 boxed::BoxedSlice,
3 sync::{ArcSlice, WeakSlice},
4 vec::Vec,
5 AllocationError, IAlloc,
6};
7use core::hash::Hash;
8
9#[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 pub const fn new() -> Self {
20 Self { inner: Vec::new() }
21 }
22}
23impl<Alloc: IAlloc> String<Alloc> {
24 pub const fn new_in(alloc: Alloc) -> Self {
26 Self {
27 inner: Vec::new_in(alloc),
28 }
29 }
30 pub const fn as_str(&self) -> &str {
32 unsafe { core::str::from_utf8_unchecked(self.inner.as_slice()) }
33 }
34 #[rustversion::attr(since(1.86), const)]
36 pub fn as_str_mut(&mut self) -> &mut str {
37 unsafe { core::str::from_utf8_unchecked_mut(self.inner.as_slice_mut()) }
38 }
39 fn try_concat_str(&mut self, s: &str) -> Result<(), AllocationError> {
40 self.inner.try_copy_extend(s.as_bytes())
41 }
42 pub fn try_concat<S: AsRef<str> + ?Sized>(&mut self, s: &S) -> Result<(), AllocationError> {
46 self.try_concat_str(s.as_ref())
47 }
48}
49impl<Alloc: IAlloc + Default> Default for String<Alloc> {
50 fn default() -> Self {
51 Self {
52 inner: Vec::default(),
53 }
54 }
55}
56impl<S: AsRef<str> + ?Sized, Alloc: IAlloc> core::ops::Add<&S> for String<Alloc> {
57 type Output = Self;
58 #[allow(clippy::arithmetic_side_effects)]
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 #[allow(clippy::arithmetic_side_effects)]
136 fn from(value: &str) -> Self {
137 Self::default() + value
138 }
139}
140
141impl<Alloc: IAlloc + Default> From<crate::str::Str<'_>> for String<Alloc> {
142 #[allow(clippy::arithmetic_side_effects)]
143 fn from(value: crate::str::Str<'_>) -> Self {
144 Self::default() + value.as_ref()
145 }
146}
147
148#[crate::stabby]
150pub struct ArcStr<Alloc: IAlloc = super::DefaultAllocator> {
151 inner: ArcSlice<u8, Alloc>,
152}
153impl<Alloc: IAlloc> ArcStr<Alloc> {
154 pub const fn as_str(&self) -> &str {
156 unsafe { core::str::from_utf8_unchecked(self.inner.as_slice()) }
157 }
158 #[rustversion::attr(since(1.86), const)]
162 pub unsafe fn as_str_mut_unchecked(&mut self) -> &mut str {
163 unsafe { core::str::from_utf8_unchecked_mut(self.inner.as_slice_mut_unchecked()) }
164 }
165 pub fn as_str_mut(&mut self) -> Option<&mut str> {
167 Self::is_unique(self).then(|| unsafe { self.as_str_mut_unchecked() })
168 }
169 pub fn is_unique(this: &Self) -> bool {
171 ArcSlice::is_unique(&this.inner)
172 }
173}
174impl<Alloc: IAlloc> AsRef<str> for ArcStr<Alloc> {
175 fn as_ref(&self) -> &str {
176 self.as_str()
177 }
178}
179
180impl<Alloc: IAlloc> core::fmt::Debug for ArcStr<Alloc> {
181 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
182 core::fmt::Debug::fmt(self.as_str(), f)
183 }
184}
185impl<Alloc: IAlloc> core::fmt::Display for ArcStr<Alloc> {
186 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
187 core::fmt::Display::fmt(self.as_str(), f)
188 }
189}
190impl<Alloc: IAlloc> core::ops::Deref for ArcStr<Alloc> {
191 type Target = str;
192 fn deref(&self) -> &Self::Target {
193 self.as_str()
194 }
195}
196impl<Alloc: IAlloc> From<String<Alloc>> for ArcStr<Alloc> {
197 fn from(value: String<Alloc>) -> Self {
198 Self {
199 inner: value.inner.into(),
200 }
201 }
202}
203impl<Alloc: IAlloc> TryFrom<ArcStr<Alloc>> for String<Alloc> {
204 type Error = ArcStr<Alloc>;
205 fn try_from(value: ArcStr<Alloc>) -> Result<Self, ArcStr<Alloc>> {
206 match value.inner.try_into() {
207 Ok(vec) => Ok(String { inner: vec }),
208 Err(slice) => Err(ArcStr { inner: slice }),
209 }
210 }
211}
212impl<Alloc: IAlloc> Clone for ArcStr<Alloc> {
213 fn clone(&self) -> Self {
214 Self {
215 inner: self.inner.clone(),
216 }
217 }
218}
219impl<Alloc: IAlloc> Eq for ArcStr<Alloc> {}
220impl<Alloc: IAlloc> PartialEq for ArcStr<Alloc> {
221 fn eq(&self, other: &Self) -> bool {
222 self.as_str() == other.as_str()
223 }
224}
225impl<Alloc: IAlloc> Ord for ArcStr<Alloc> {
226 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
227 self.as_str().cmp(other.as_str())
228 }
229}
230impl<Alloc: IAlloc> PartialOrd for ArcStr<Alloc> {
231 fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
232 Some(self.cmp(other))
233 }
234}
235impl<Alloc: IAlloc> Hash for ArcStr<Alloc> {
236 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
237 self.as_str().hash(state)
238 }
239}
240
241#[crate::stabby]
243pub struct WeakStr<Alloc: IAlloc = super::DefaultAllocator> {
244 inner: WeakSlice<u8, Alloc>,
245}
246impl<Alloc: IAlloc> WeakStr<Alloc> {
247 pub fn upgrade(&self) -> Option<ArcStr<Alloc>> {
249 self.inner.upgrade().map(|inner| ArcStr { inner })
250 }
251 pub fn force_upgrade(&self) -> ArcStr<Alloc> {
255 ArcStr {
256 inner: self.inner.force_upgrade(),
257 }
258 }
259}
260impl<Alloc: IAlloc> From<&ArcStr<Alloc>> for WeakStr<Alloc> {
261 fn from(value: &ArcStr<Alloc>) -> Self {
262 Self {
263 inner: (&value.inner).into(),
264 }
265 }
266}
267impl<Alloc: IAlloc> Clone for WeakStr<Alloc> {
268 fn clone(&self) -> Self {
269 Self {
270 inner: self.inner.clone(),
271 }
272 }
273}
274
275#[crate::stabby]
277pub struct BoxedStr<Alloc: IAlloc = super::DefaultAllocator> {
278 inner: BoxedSlice<u8, Alloc>,
279}
280impl<Alloc: IAlloc> BoxedStr<Alloc> {
281 pub const fn as_str(&self) -> &str {
283 unsafe { core::str::from_utf8_unchecked(self.inner.as_slice()) }
284 }
285 #[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::de::{Error, Unexpected, Visitor};
375 use serde::{Deserialize, Serialize};
376 impl<Alloc: IAlloc> Serialize for String<Alloc> {
377 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
378 where
379 S: serde::Serializer,
380 {
381 serializer.serialize_str(self)
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 deserializer.deserialize_string(StringVisitor(core::marker::PhantomData))
390 }
391 }
392 struct StringVisitor<A: IAlloc>(core::marker::PhantomData<crate::alloc::string::String<A>>);
393 impl<'a, Alloc: IAlloc + Default> Visitor<'a> for StringVisitor<Alloc> {
394 type Value = String<Alloc>;
395 fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
396 Ok(v.into())
397 }
398
399 #[cfg(feature = "std")]
400 fn visit_string<E: Error>(self, v: std::string::String) -> Result<Self::Value, E> {
401 Ok(v.into())
402 }
403
404 fn visit_bytes<E: Error>(self, v: &[u8]) -> Result<Self::Value, E> {
405 core::str::from_utf8(v)
406 .map_err(|_| Error::invalid_value(Unexpected::Bytes(v), &self))
407 .map(Into::into)
408 }
409
410 #[cfg(feature = "std")]
411 fn visit_byte_buf<E: Error>(self, v: std::vec::Vec<u8>) -> Result<Self::Value, E> {
412 std::string::String::from_utf8(v)
413 .map_err(|e| Error::invalid_value(Unexpected::Bytes(&e.into_bytes()), &self))
414 .map(Into::into)
415 }
416
417 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
418 write!(formatter, "a string")
419 }
420 }
421}