@@ -4,8 +4,8 @@ use core::{
44 borrow,
55 char:: DecodeUtf16Error ,
66 cmp:: Ordering ,
7- fmt ,
8- fmt:: { Arguments , Write } ,
7+ error :: Error ,
8+ fmt:: { self , Arguments , Display , Write } ,
99 hash, iter,
1010 ops:: { self , Range , RangeBounds } ,
1111 str:: { self , Utf8Error } ,
@@ -23,6 +23,63 @@ use crate::{
2323mod drain;
2424pub use drain:: Drain ;
2525
26+ /// Error type of the [`String::from_utf8`] function.
27+ ///
28+ /// [`Self::into_bytes`] will give back the byte vector which was used in the conversion attempt.
29+ ///
30+ /// Equivalent of `std::string::FromUtf8Error`.
31+ ///
32+ /// # Examples
33+ ///
34+ /// ```
35+ /// use heapless::{String, Vec, string::FromUtf8Error};
36+ ///
37+ /// let data = [0, 159, 146, 150];
38+ /// let mut vec = Vec::<u8, 4>::new();
39+ /// vec.extend_from_slice(&data);
40+ ///
41+ /// let e: FromUtf8Error<4> = String::from_utf8(vec).unwrap_err();
42+ ///
43+ /// assert_eq!(e.utf8_error().valid_up_to(), 1);
44+ /// assert_eq!(e.as_bytes(), &data);
45+ /// assert_eq!(e.into_bytes(), data);
46+ /// ```
47+ #[ derive( Debug , Clone , PartialEq , Eq ) ]
48+ pub struct FromUtf8Error < const N : usize , LenT : LenType = usize > {
49+ bytes : Vec < u8 , N , LenT > ,
50+ error : Utf8Error ,
51+ }
52+
53+ impl < const N : usize , LenT : LenType > FromUtf8Error < N , LenT > {
54+ /// Returns a slice of [`u8`]s bytes that were attempted to convert to a [`String`].
55+ pub fn as_bytes ( & self ) -> & [ u8 ] {
56+ & self . bytes
57+ }
58+
59+ /// Returns the bytes that were attempted to convert to a [`String`].
60+ pub fn into_bytes ( self ) -> Vec < u8 , N , LenT > {
61+ self . bytes
62+ }
63+
64+ /// Fetch the [`Utf8Error`] to get more details about the conversion failure.
65+ pub fn utf8_error ( & self ) -> Utf8Error {
66+ self . error
67+ }
68+ }
69+
70+ impl < const N : usize , LenT : LenType > Display for FromUtf8Error < N , LenT > {
71+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
72+ core:: fmt:: Display :: fmt ( & self , f)
73+ }
74+ }
75+
76+ impl < const N : usize , LenT : LenType > Error for FromUtf8Error < N , LenT > {
77+ /// returns the underlying [`Utf8Error`]
78+ fn source ( & self ) -> Option < & ( dyn Error + ' static ) > {
79+ Some ( & self . error )
80+ }
81+ }
82+
2683/// A possible error value when converting a [`String`] from a UTF-16 byte slice.
2784///
2885/// This type is the error type for the [`from_utf16`] method on [`String`].
@@ -219,6 +276,13 @@ impl<LenT: LenType, const N: usize> String<N, LenT> {
219276
220277 /// Convert UTF-8 bytes into a `String`.
221278 ///
279+ /// # Errors
280+ ///
281+ /// Returns [`Err`] if the bytes are not valid UTF-8. The error includes
282+ /// a description as to why the bytes are not UTF-8.
283+ /// The error also contains the moved [`Vec`], such that
284+ /// you can regain ownership of it.
285+ ///
222286 /// # Examples
223287 ///
224288 /// Basic usage:
@@ -231,25 +295,28 @@ impl<LenT: LenType, const N: usize> String<N, LenT> {
231295 ///
232296 /// let sparkle_heart: String<4> = String::from_utf8(sparkle_heart)?;
233297 /// assert_eq!("💖", sparkle_heart);
234- /// # Ok::<(), core::str::Utf8Error >(())
298+ /// # Ok::<(), heapless::string::FromUtf8Error<4> >(())
235299 /// ```
236300 ///
237301 /// Invalid UTF-8:
238302 ///
239303 /// ```
240- /// use core::str::Utf8Error;
241- /// use heapless::{String, Vec};
304+ /// use heapless::{String, Vec, string::FromUtf8Error};
242305 ///
306+ /// let data = [0, 159, 146, 150];
243307 /// let mut vec = Vec::<u8, 4>::new();
244- /// vec.extend_from_slice(&[0, 159, 146, 150] );
308+ /// vec.extend_from_slice(&data );
245309 ///
246- /// let e: Utf8Error = String::from_utf8(vec).unwrap_err();
247- /// assert_eq!(e.valid_up_to(), 1);
248- /// # Ok::<(), core::str::Utf8Error>(())
310+ /// let e: FromUtf8Error<4> = String::from_utf8(vec).unwrap_err();
311+ /// assert_eq!(e.utf8_error().valid_up_to(), 1);
312+ /// assert_eq!(e.into_bytes(), data);
313+ /// # Ok::<(), heapless::string::FromUtf8Error<4>>(())
249314 /// ```
250315 #[ inline]
251- pub fn from_utf8 ( vec : Vec < u8 , N , LenT > ) -> Result < Self , Utf8Error > {
252- core:: str:: from_utf8 ( & vec) ?;
316+ pub fn from_utf8 ( vec : Vec < u8 , N , LenT > ) -> Result < Self , FromUtf8Error < N , LenT > > {
317+ if let Err ( error) = core:: str:: from_utf8 ( & vec) {
318+ return Err ( FromUtf8Error { bytes : vec, error } ) ;
319+ }
253320
254321 // SAFETY: UTF-8 invariant has just been checked by `str::from_utf8`.
255322 Ok ( unsafe { Self :: from_utf8_unchecked ( vec) } )
0 commit comments