musli_core/alloc/
string.rs

1use core::borrow::Borrow;
2use core::cmp::Ordering;
3use core::error::Error;
4use core::fmt;
5use core::ops::Deref;
6use core::str::{self, Utf8Error};
7
8#[cfg(feature = "alloc")]
9use rust_alloc::borrow::Cow;
10
11use crate::de::UnsizedVisitor;
12use crate::{Context, Decode, Decoder, Encode, Encoder};
13
14use super::{AllocError, Allocator, GlobalAllocator, Vec};
15
16/// Collect a string into a string buffer.
17#[inline]
18pub(crate) fn collect_string<A>(alloc: A, value: impl fmt::Display) -> Result<String<A>, AllocError>
19where
20    A: Allocator,
21{
22    use core::fmt::Write;
23
24    let mut string = String::new_in(alloc);
25
26    if write!(string, "{value}").is_err() {
27        return Err(AllocError);
28    }
29
30    Ok(string)
31}
32
33/// A Müsli-allocated UTF-8–encoded, growable string.
34///
35/// `String` is the most common string type. It has ownership over the contents
36/// of the string, stored in a allocated buffer. It is closely related to its
37/// borrowed counterpart, the primitive [`str`].
38///
39/// This is a [`String`][alloc-string] style type capable of using the
40/// [`Allocator`] provided through a [`Context`]. Therefore it can be safely
41/// used in no-alloc environments.
42///
43/// [alloc-string]: rust_alloc::string::String
44/// [`str`]: prim@str
45pub struct String<A>
46where
47    A: Allocator,
48{
49    vec: Vec<u8, A>,
50}
51
52/// A possible error value when converting a `String` from a UTF-8 byte vector.
53///
54/// This type is the error type for the [`from_utf8`] method on [`String`]. It
55/// is designed in such a way to carefully avoid reallocations: the
56/// [`into_bytes`] method will give back the byte vector that was used in the
57/// conversion attempt.
58///
59/// [`from_utf8`]: String::from_utf8
60/// [`into_bytes`]: FromUtf8Error::into_bytes
61///
62/// The [`Utf8Error`] type provided by [`std::str`] represents an error that may
63/// occur when converting a slice of [`u8`]s to a [`&str`]. In this sense, it's
64/// an analogue to `FromUtf8Error`, and you can get one from a `FromUtf8Error`
65/// through the [`utf8_error`] method.
66///
67/// [`Utf8Error`]: str::Utf8Error "std::str::Utf8Error"
68/// [`std::str`]: core::str "std::str"
69/// [`&str`]: prim@str "&str"
70/// [`utf8_error`]: FromUtf8Error::utf8_error
71///
72/// # Examples
73///
74/// ```
75/// // some invalid bytes, in a vector
76/// let bytes = vec![0, 159];
77///
78/// let value = String::from_utf8(bytes);
79///
80/// assert!(value.is_err());
81/// assert_eq!(vec![0, 159], value.unwrap_err().into_bytes());
82/// ```
83pub struct FromUtf8Error<A>
84where
85    A: Allocator,
86{
87    bytes: Vec<u8, A>,
88    error: Utf8Error,
89}
90
91impl<A> String<A>
92where
93    A: Allocator,
94{
95    /// Creates a new empty `String`.
96    ///
97    /// Given that the `String` is empty, this will not allocate any initial
98    /// buffer. While that means that this initial operation is very
99    /// inexpensive, it may cause excessive allocation later when you add data.
100    /// If you have an idea of how much data the `String` will hold, consider
101    /// the [`with_capacity_in`] method to prevent excessive re-allocation.
102    ///
103    /// [`with_capacity_in`]: String::with_capacity_in
104    ///
105    /// # Examples
106    ///
107    /// ```
108    /// use musli::alloc::{AllocError, String};
109    ///
110    /// musli::alloc::default(|alloc| {
111    ///     _ = String::new_in(alloc);
112    ///     Ok::<_, AllocError>(())
113    /// });
114    /// # Ok::<_, AllocError>(())
115    /// ```
116    #[inline]
117    pub fn new_in(alloc: A) -> Self {
118        Self {
119            vec: Vec::new_in(alloc),
120        }
121    }
122
123    /// Creates a new empty `String` with at least the specified capacity.
124    ///
125    /// `String`s have an internal buffer to hold their data. The capacity is
126    /// the length of that buffer, and can be queried with the [`capacity`]
127    /// method. This method creates an empty `String`, but one with an initial
128    /// buffer that can hold at least `capacity` bytes. This is useful when you
129    /// may be appending a bunch of data to the `String`, reducing the number of
130    /// reallocations it needs to do.
131    ///
132    /// [`capacity`]: String::capacity
133    ///
134    /// If the given capacity is `0`, no allocation will occur, and this method
135    /// is identical to the [`new_in`] method.
136    ///
137    /// [`new_in`]: String::new_in
138    ///
139    /// # Examples
140    ///
141    /// ```
142    /// use musli::alloc::{AllocError, String};
143    ///
144    /// musli::alloc::default(|alloc| {
145    ///     let mut s = String::with_capacity_in(10, alloc)?;
146    ///
147    ///     // The String contains no chars, even though it has capacity for more
148    ///     assert_eq!(s.len(), 0);
149    ///
150    ///     // These are all done without reallocating...
151    ///     let cap = s.capacity();
152    ///
153    ///     for _ in 0..10 {
154    ///         s.push('a')?;
155    ///     }
156    ///
157    ///     assert_eq!(s.capacity(), cap);
158    ///
159    ///     // ...but this may make the string reallocate
160    ///     s.push('a')?;
161    ///     Ok::<_, AllocError>(())
162    /// })?;
163    /// # Ok::<_, AllocError>(())
164    /// ```
165    #[inline]
166    pub fn with_capacity_in(capacity: usize, alloc: A) -> Result<Self, AllocError> {
167        Ok(Self {
168            vec: Vec::with_capacity_in(capacity, alloc)?,
169        })
170    }
171
172    /// Coerce into a std string.
173    #[cfg(feature = "alloc")]
174    pub fn into_std(self) -> Result<rust_alloc::string::String, Self> {
175        match self.vec.into_std() {
176            Ok(vec) => {
177                // SAFETY: The buffer is guaranteed to be valid utf-8.
178                unsafe { Ok(rust_alloc::string::String::from_utf8_unchecked(vec)) }
179            }
180            Err(vec) => Err(Self { vec }),
181        }
182    }
183
184    /// Converts a vector of bytes to a `String`.
185    ///
186    /// A string ([`String`]) is made of bytes ([`u8`]), and a vector of bytes
187    /// ([`Vec<u8>`]) is made of bytes, so this function converts between the
188    /// two. Not all byte slices are valid `String`s, however: `String` requires
189    /// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes
190    /// are valid UTF-8, and then does the conversion.
191    ///
192    /// If you are sure that the byte slice is valid UTF-8, and you don't want
193    /// to incur the overhead of the validity check, there is an unsafe version
194    /// of this function, [`from_utf8_unchecked`], which has the same behavior
195    /// but skips the check.
196    ///
197    /// This method will take care to not copy the vector, for efficiency's
198    /// sake.
199    ///
200    /// If you need a [`&str`] instead of a `String`, consider
201    /// [`str::from_utf8`].
202    ///
203    /// The inverse of this method is [`into_bytes`].
204    ///
205    /// # Errors
206    ///
207    /// Returns [`Err`] if the slice is not UTF-8 with a description as to why
208    /// the provided bytes are not UTF-8. The vector you moved in is also
209    /// included.
210    ///
211    /// # Examples
212    ///
213    /// Basic usage:
214    ///
215    /// ```
216    /// use musli::alloc::{AllocError, Vec, String};
217    ///
218    /// musli::alloc::default(|alloc| {
219    ///     let mut sparkle_heart = Vec::<u8, _>::new_in(alloc);
220    ///     // some bytes, in a vector
221    ///     sparkle_heart.extend_from_slice(&[240, 159, 146, 150])?;
222    ///
223    ///     let sparkle_heart = String::from_utf8(sparkle_heart).unwrap();
224    ///
225    ///     assert_eq!("💖", sparkle_heart);
226    ///     Ok::<_, AllocError>(())
227    /// });
228    /// # Ok::<_, AllocError>(())
229    /// ```
230    ///
231    /// Incorrect bytes:
232    ///
233    /// ```
234    /// use musli::alloc::{AllocError, Vec, String};
235    ///
236    /// musli::alloc::default(|alloc| {
237    ///     let mut sparkle_heart = Vec::<u8, _>::new_in(alloc);
238    ///     // some bytes, in a vector
239    ///     sparkle_heart.extend_from_slice(&[0, 159, 146, 150])?;
240    ///
241    ///     assert!(String::from_utf8(sparkle_heart).is_err());
242    ///     Ok::<_, AllocError>(())
243    /// });
244    /// # Ok::<_, AllocError>(())
245    /// ```
246    ///
247    /// See the docs for [`FromUtf8Error`] for more details on what you can do
248    /// with this error.
249    ///
250    /// [`from_utf8_unchecked`]: String::from_utf8_unchecked
251    /// [`Vec<u8>`]: crate::alloc::Vec "Vec"
252    /// [`&str`]: prim@str "&str"
253    /// [`into_bytes`]: String::into_bytes
254    #[inline]
255    pub fn from_utf8(vec: Vec<u8, A>) -> Result<String<A>, FromUtf8Error<A>> {
256        match str::from_utf8(&vec) {
257            Ok(..) => Ok(String { vec }),
258            Err(e) => Err(FromUtf8Error {
259                bytes: vec,
260                error: e,
261            }),
262        }
263    }
264
265    /// Converts a vector of bytes to a `String` without checking that the
266    /// string contains valid UTF-8.
267    ///
268    /// See the safe version, [`from_utf8`], for more details.
269    ///
270    /// [`from_utf8`]: String::from_utf8
271    ///
272    /// # Safety
273    ///
274    /// This function is unsafe because it does not check that the bytes passed
275    /// to it are valid UTF-8. If this constraint is violated, it may cause
276    /// memory unsafety issues with future users of the `String`, as the rest of
277    /// the standard library assumes that `String`s are valid UTF-8.
278    ///
279    /// # Examples
280    ///
281    /// ```
282    /// use musli::alloc::{AllocError, Vec, String};
283    ///
284    /// musli::alloc::default(|alloc| {
285    ///     let mut sparkle_heart = Vec::<u8, _>::new_in(alloc);
286    ///     // some bytes, in a vector
287    ///     sparkle_heart.extend_from_slice(&[240, 159, 146, 150])?;
288    ///
289    ///     let sparkle_heart = unsafe {
290    ///         String::from_utf8_unchecked(sparkle_heart)
291    ///     };
292    ///
293    ///     assert_eq!("💖", sparkle_heart);
294    ///     Ok::<_, AllocError>(())
295    /// });
296    /// # Ok::<_, AllocError>(())
297    /// ```
298    #[inline]
299    #[must_use]
300    pub unsafe fn from_utf8_unchecked(vec: Vec<u8, A>) -> String<A> {
301        String { vec }
302    }
303
304    /// Converts a `String` into a byte vector.
305    ///
306    /// This consumes the `String`, so we do not need to copy its contents.
307    ///
308    /// # Examples
309    ///
310    /// ```
311    /// use musli::alloc::{AllocError, String};
312    ///
313    /// musli::alloc::default(|alloc| {
314    ///     let mut s = String::new_in(alloc);
315    ///     s.push_str("hello")?;
316    ///     let bytes = s.into_bytes();
317    ///
318    ///     assert_eq!(&[104, 101, 108, 108, 111][..], &bytes[..]);
319    ///     Ok::<_, AllocError>(())
320    /// });
321    /// # Ok::<_, AllocError>(())
322    /// ```
323    #[inline]
324    #[must_use = "`self` will be dropped if the result is not used"]
325    pub fn into_bytes(self) -> Vec<u8, A> {
326        self.vec
327    }
328
329    /// Extracts a string slice containing the entire `String`.
330    ///
331    /// # Examples
332    ///
333    /// ```
334    /// use musli::alloc::{AllocError, String};
335    ///
336    /// musli::alloc::default(|alloc| {
337    ///     let mut s = String::new_in(alloc);
338    ///     s.push_str("foo")?;
339    ///     assert_eq!(s.as_str(), "foo");
340    ///     Ok::<_, AllocError>(())
341    /// });
342    /// # Ok::<_, AllocError>(())
343    /// ```
344    #[inline]
345    pub fn as_str(&self) -> &str {
346        // SAFETY: Interactions ensure that data is valid utf-8.
347        unsafe { str::from_utf8_unchecked(self.vec.as_slice()) }
348    }
349
350    /// Appends the given [`char`] to the end of this `String`.
351    ///
352    /// # Examples
353    ///
354    /// ```
355    /// use musli::alloc::{AllocError, String};
356    ///
357    /// musli::alloc::default(|alloc| {
358    ///     let mut s = String::new_in(alloc);
359    ///
360    ///     s.push_str("abc")?;
361    ///
362    ///     s.push('1')?;
363    ///     s.push('2')?;
364    ///     s.push('3')?;
365    ///
366    ///     assert_eq!("abc123", s);
367    ///     Ok::<_, AllocError>(())
368    /// });
369    /// # Ok::<_, AllocError>(())
370    /// ```
371    #[inline]
372    pub fn push(&mut self, c: char) -> Result<(), AllocError> {
373        self.vec
374            .extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
375    }
376
377    /// Appends a given string slice onto the end of this `String`.
378    ///
379    /// # Examples
380    ///
381    /// ```
382    /// use musli::alloc::{AllocError, String};
383    ///
384    /// musli::alloc::default(|alloc| {
385    ///     let mut a = String::new_in(alloc);
386    ///
387    ///     a.push_str("Hello")?;
388    ///     a.push_str(" World")?;
389    ///
390    ///     assert_eq!(a.as_str(), "Hello World");
391    ///     Ok::<_, AllocError>(())
392    /// });
393    /// # Ok::<_, AllocError>(())
394    /// ```
395    #[inline]
396    pub fn push_str(&mut self, s: &str) -> Result<(), AllocError> {
397        self.vec.extend_from_slice(s.as_bytes())
398    }
399
400    /// Returns this `String`'s capacity, in bytes.
401    ///
402    /// # Examples
403    ///
404    /// ```
405    /// use musli::alloc::{AllocError, String};
406    ///
407    /// musli::alloc::default(|alloc| {
408    ///     let s = String::with_capacity_in(10, alloc)?;
409    ///
410    ///     assert!(s.capacity() >= 10);
411    ///     Ok::<_, AllocError>(())
412    /// });
413    /// # Ok::<_, AllocError>(())
414    /// ```
415    #[inline]
416    #[must_use]
417    pub fn capacity(&self) -> usize {
418        self.vec.capacity()
419    }
420
421    /// Returns the length of this `String`, in bytes, not [`char`]s or
422    /// graphemes. In other words, it might not be what a human considers the
423    /// length of the string.
424    ///
425    /// # Examples
426    ///
427    /// ```
428    /// use musli::alloc::{AllocError, String};
429    ///
430    /// musli::alloc::default(|alloc| {
431    ///     let mut a = String::new_in(alloc);
432    ///     a.push_str("foo")?;
433    ///     assert_eq!(a.len(), 3);
434    ///
435    ///     let mut fancy_f = String::new_in(alloc);
436    ///     fancy_f.push_str("ƒoo")?;
437    ///     assert_eq!(fancy_f.len(), 4);
438    ///     assert_eq!(fancy_f.chars().count(), 3);
439    ///     Ok::<_, AllocError>(())
440    /// })?;
441    /// # Ok::<_, AllocError>(())
442    /// ```
443    #[inline]
444    #[must_use]
445    pub fn len(&self) -> usize {
446        self.vec.len()
447    }
448
449    /// Returns `true` if this `String` has a length of zero, and `false`
450    /// otherwise.
451    ///
452    /// # Examples
453    ///
454    /// ```
455    /// use musli::alloc::{AllocError, String};
456    ///
457    /// musli::alloc::default(|alloc| {
458    ///     let mut v = String::new_in(alloc);
459    ///     assert!(v.is_empty());
460    ///
461    ///     v.push('a')?;
462    ///     assert!(!v.is_empty());
463    ///     Ok::<_, AllocError>(())
464    /// })?;
465    /// # Ok::<_, AllocError>(())
466    /// ```
467    #[inline]
468    #[must_use]
469    pub fn is_empty(&self) -> bool {
470        self.len() == 0
471    }
472}
473
474impl<A> Clone for String<A>
475where
476    A: GlobalAllocator,
477{
478    #[inline]
479    fn clone(&self) -> Self {
480        Self {
481            vec: self.vec.clone(),
482        }
483    }
484}
485
486impl<A> fmt::Write for String<A>
487where
488    A: Allocator,
489{
490    #[inline]
491    fn write_char(&mut self, c: char) -> fmt::Result {
492        self.push(c).map_err(|_| fmt::Error)
493    }
494
495    #[inline]
496    fn write_str(&mut self, s: &str) -> fmt::Result {
497        self.push_str(s).map_err(|_| fmt::Error)
498    }
499}
500
501impl<A> Deref for String<A>
502where
503    A: Allocator,
504{
505    type Target = str;
506
507    #[inline]
508    fn deref(&self) -> &str {
509        unsafe { str::from_utf8_unchecked(self.vec.as_slice()) }
510    }
511}
512
513impl<A> fmt::Display for String<A>
514where
515    A: Allocator,
516{
517    #[inline]
518    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
519        self.as_str().fmt(f)
520    }
521}
522
523impl<A> fmt::Debug for String<A>
524where
525    A: Allocator,
526{
527    #[inline]
528    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
529        self.as_str().fmt(f)
530    }
531}
532
533impl<A> AsRef<str> for String<A>
534where
535    A: Allocator,
536{
537    #[inline]
538    fn as_ref(&self) -> &str {
539        self.as_str()
540    }
541}
542
543impl<A> PartialEq for String<A>
544where
545    A: Allocator,
546{
547    #[inline]
548    fn eq(&self, other: &Self) -> bool {
549        self.as_str().eq(other.as_str())
550    }
551}
552
553impl<A> Eq for String<A> where A: Allocator {}
554
555impl<A> PartialOrd for String<A>
556where
557    A: Allocator,
558{
559    #[inline]
560    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
561        Some(self.cmp(other))
562    }
563}
564
565impl<A> Ord for String<A>
566where
567    A: Allocator,
568{
569    #[inline]
570    fn cmp(&self, other: &Self) -> Ordering {
571        self.as_str().cmp(other.as_str())
572    }
573}
574
575impl<A> Borrow<str> for String<A>
576where
577    A: Allocator,
578{
579    #[inline]
580    fn borrow(&self) -> &str {
581        self
582    }
583}
584
585macro_rules! impl_eq {
586    ($lhs:ty, $rhs: ty) => {
587        #[allow(unused_lifetimes)]
588        impl<'a, 'b, A> PartialEq<$rhs> for $lhs
589        where
590            A: Allocator,
591        {
592            #[inline]
593            fn eq(&self, other: &$rhs) -> bool {
594                PartialEq::eq(&self[..], &other[..])
595            }
596
597            #[inline]
598            #[allow(clippy::partialeq_ne_impl)]
599            fn ne(&self, other: &$rhs) -> bool {
600                PartialEq::ne(&self[..], &other[..])
601            }
602        }
603
604        #[allow(unused_lifetimes)]
605        impl<'a, 'b, A> PartialEq<$lhs> for $rhs
606        where
607            A: Allocator,
608        {
609            #[inline]
610            fn eq(&self, other: &$lhs) -> bool {
611                PartialEq::eq(&self[..], &other[..])
612            }
613
614            #[inline]
615            #[allow(clippy::partialeq_ne_impl)]
616            fn ne(&self, other: &$lhs) -> bool {
617                PartialEq::ne(&self[..], &other[..])
618            }
619        }
620    };
621}
622
623impl_eq! { String<A>, str }
624impl_eq! { String<A>, &'a str }
625#[cfg(feature = "alloc")]
626impl_eq! { Cow<'a, str>, String<A> }
627
628/// Conversion from a std [`String`][std-string] to a Müsli-allocated [`String`]
629/// in a [`GlobalAllocator`] allocator.
630///
631/// [std-string]: rust_alloc::string::String
632///
633/// # Examples
634///
635/// ```
636/// use musli::alloc::{String, Global};
637///
638/// let value = std::string::String::from("Hello World");
639/// let value2 = String::<Global>::from(value);
640/// ```
641#[cfg(feature = "alloc")]
642#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))]
643impl<A> From<rust_alloc::string::String> for String<A>
644where
645    A: GlobalAllocator,
646{
647    #[inline]
648    fn from(value: rust_alloc::string::String) -> Self {
649        Self {
650            vec: Vec::from(value.into_bytes()),
651        }
652    }
653}
654
655impl<A> fmt::Display for FromUtf8Error<A>
656where
657    A: Allocator,
658{
659    #[inline]
660    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
661        fmt::Display::fmt(&self.error, f)
662    }
663}
664
665impl<A> Error for FromUtf8Error<A> where A: Allocator {}
666
667impl<A, B> PartialEq<FromUtf8Error<B>> for FromUtf8Error<A>
668where
669    A: Allocator,
670    B: Allocator,
671{
672    #[inline]
673    fn eq(&self, other: &FromUtf8Error<B>) -> bool {
674        self.bytes == other.bytes && self.error == other.error
675    }
676}
677
678impl<A> fmt::Debug for FromUtf8Error<A>
679where
680    A: Allocator,
681{
682    #[inline]
683    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
684        f.debug_struct("FromUtf8Error")
685            .field("bytes", &self.bytes)
686            .field("error", &self.error)
687            .finish()
688    }
689}
690
691impl<A> FromUtf8Error<A>
692where
693    A: Allocator,
694{
695    /// Returns a slice of [`u8`]s bytes that were attempted to convert to a
696    /// `String`.
697    ///
698    /// # Examples
699    ///
700    /// ```
701    /// use musli::alloc::{AllocError, Vec, String};
702    ///
703    /// musli::alloc::default(|alloc| {
704    ///     let mut bytes = Vec::new_in(alloc);
705    ///     // some invalid bytes, in a vector
706    ///     bytes.extend_from_slice(&[0, 159])?;
707    ///
708    ///     let value = String::from_utf8(bytes);
709    ///
710    ///     assert_eq!(&[0, 159], value.unwrap_err().as_bytes());
711    ///     Ok::<_, AllocError>(())
712    /// });
713    /// # Ok::<_, AllocError>(())
714    /// ```
715    #[inline]
716    #[must_use]
717    pub fn as_bytes(&self) -> &[u8] {
718        &self.bytes[..]
719    }
720
721    /// Returns the bytes that were attempted to convert to a `String`.
722    ///
723    /// This method is carefully constructed to avoid allocation. It will
724    /// consume the error, moving out the bytes, so that a copy of the bytes
725    /// does not need to be made.
726    ///
727    /// # Examples
728    ///
729    /// ```
730    /// use musli::alloc::{AllocError, Vec, String};
731    ///
732    /// musli::alloc::default(|alloc| {
733    ///     let mut bytes = Vec::new_in(alloc);
734    ///     // some invalid bytes, in a vector
735    ///     bytes.extend_from_slice(&[0, 159])?;
736    ///
737    ///     let value = String::from_utf8(bytes);
738    ///
739    ///     assert_eq!(&[0, 159], value.unwrap_err().into_bytes());
740    ///     Ok::<_, AllocError>(())
741    /// });
742    /// # Ok::<_, AllocError>(())
743    /// ```
744    #[inline]
745    #[must_use = "`self` will be dropped if the result is not used"]
746    pub fn into_bytes(self) -> Vec<u8, A> {
747        self.bytes
748    }
749
750    /// Fetch a `Utf8Error` to get more details about the conversion failure.
751    ///
752    /// The [`Utf8Error`] type provided by [`std::str`] represents an error that
753    /// may occur when converting a slice of [`u8`]s to a [`&str`]. In this
754    /// sense, it's an analogue to `FromUtf8Error`. See its documentation for
755    /// more details on using it.
756    ///
757    /// [`std::str`]: core::str "std::str"
758    /// [`&str`]: prim@str "&str"
759    ///
760    /// # Examples
761    ///
762    /// ```
763    /// use musli::alloc::{AllocError, Vec, String};
764    ///
765    /// musli::alloc::default(|alloc| {
766    ///     let mut bytes = Vec::new_in(alloc);
767    ///     // some invalid bytes, in a vector
768    ///     bytes.extend_from_slice(&[0, 159])?;
769    ///
770    ///     let value = String::from_utf8(bytes);
771    ///
772    ///     let error = value.unwrap_err().utf8_error();
773    ///     // the first byte is invalid here
774    ///     assert_eq!(1, error.valid_up_to());
775    ///     Ok::<_, AllocError>(())
776    /// });
777    /// # Ok::<_, AllocError>(())
778    /// ```
779    #[inline]
780    #[must_use]
781    pub fn utf8_error(&self) -> Utf8Error {
782        self.error
783    }
784}
785
786impl<M, A> Encode<M> for String<A>
787where
788    A: Allocator,
789{
790    type Encode = str;
791
792    const IS_BITWISE_ENCODE: bool = false;
793
794    #[inline]
795    fn encode<E>(&self, encoder: E) -> Result<(), E::Error>
796    where
797        E: Encoder<Mode = M>,
798    {
799        self.as_str().encode(encoder)
800    }
801
802    #[inline]
803    fn as_encode(&self) -> &Self::Encode {
804        self
805    }
806}
807
808/// Decode implementation for a Müsli-allocated [`String`].
809///
810/// # Examples
811///
812/// ```
813/// use musli::alloc::String;
814/// use musli::{Allocator, Decode};
815///
816/// #[derive(Decode)]
817/// struct Struct<A> where A: Allocator {
818///     field: String<A>
819/// }
820/// ```
821impl<'de, M, A> Decode<'de, M, A> for String<A>
822where
823    A: Allocator,
824{
825    const IS_BITWISE_DECODE: bool = false;
826
827    #[inline]
828    fn decode<D>(decoder: D) -> Result<Self, D::Error>
829    where
830        D: Decoder<'de, Mode = M, Allocator = A>,
831    {
832        struct Visitor;
833
834        #[crate::trait_defaults(crate)]
835        impl<C> UnsizedVisitor<'_, C, str> for Visitor
836        where
837            C: Context,
838        {
839            type Ok = String<Self::Allocator>;
840
841            #[inline]
842            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
843                write!(f, "string")
844            }
845
846            #[inline]
847            fn visit_owned(
848                self,
849                _: C,
850                value: String<Self::Allocator>,
851            ) -> Result<Self::Ok, C::Error> {
852                Ok(value)
853            }
854
855            #[inline]
856            fn visit_ref(self, cx: C, string: &str) -> Result<Self::Ok, C::Error> {
857                let mut s = String::new_in(cx.alloc());
858                s.push_str(string).map_err(cx.map())?;
859                Ok(s)
860            }
861        }
862
863        decoder.decode_string(Visitor)
864    }
865}