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