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}