diff --git a/CHANGELOG.md b/CHANGELOG.md index 32753b771c..0174ee4960 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Implemented `retain` for `IndexMap` and `IndexSet`. - Recover `StableDeref` trait for `pool::object::Object` and `pool::boxed::Box`. - Add polyfills for ESP32S2 +- Added `String::from_utf8` and `String::from_utf8_unchecked`. ### Changed diff --git a/src/string.rs b/src/string.rs index a40cbb40b2..24bd95131b 100644 --- a/src/string.rs +++ b/src/string.rs @@ -1,4 +1,10 @@ -use core::{cmp::Ordering, fmt, fmt::Write, hash, iter, ops, str}; +use core::{ + cmp::Ordering, + fmt, + fmt::Write, + hash, iter, ops, + str::{self, Utf8Error}, +}; use crate::Vec; @@ -28,6 +34,68 @@ impl String { Self { vec: Vec::new() } } + /// Convert UTF-8 bytes into a `String`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use heapless::{String, Vec}; + /// + /// let mut sparkle_heart = Vec::::new(); + /// sparkle_heart.extend_from_slice(&[240, 159, 146, 150]); + /// + /// let sparkle_heart: String<4> = String::from_utf8(sparkle_heart)?; + /// assert_eq!("💖", sparkle_heart); + /// # Ok::<(), core::str::Utf8Error>(()) + /// ``` + /// + /// Invalid UTF-8: + /// + /// ``` + /// use core::str::Utf8Error; + /// use heapless::{String, Vec}; + /// + /// let mut vec = Vec::::new(); + /// vec.extend_from_slice(&[0, 159, 146, 150]); + /// + /// let e: Utf8Error = String::from_utf8(vec).unwrap_err(); + /// assert_eq!(e.valid_up_to(), 1); + /// # Ok::<(), core::str::Utf8Error>(()) + /// ``` + #[inline] + pub fn from_utf8(vec: Vec) -> Result { + core::str::from_utf8(&vec)?; + Ok(Self { vec }) + } + + /// Convert UTF-8 bytes into a `String`, without checking that the string + /// contains valid UTF-8. + /// + /// # Safety + /// + /// The bytes passed in must be valid UTF-8. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use heapless::{String, Vec}; + /// + /// let mut sparkle_heart = Vec::::new(); + /// sparkle_heart.extend_from_slice(&[240, 159, 146, 150]); + /// + /// // Safety: `sparkle_heart` Vec is known to contain valid UTF-8 + /// let sparkle_heart: String<4> = unsafe { String::from_utf8_unchecked(sparkle_heart) }; + /// assert_eq!("💖", sparkle_heart); + /// ``` + #[inline] + pub unsafe fn from_utf8_unchecked(vec: Vec) -> Self { + Self { vec } + } + /// Converts a `String` into a byte vector. /// /// This consumes the `String`, so we do not need to copy its contents.