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}