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