diff --git a/CHANGELOG.md b/CHANGELOG.md index a8a2d6dc4f..4d16fb5cbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - Added `format` macro. +- Added `String::from_utf16`. ### Changed diff --git a/src/binary_heap.rs b/src/binary_heap.rs index 3b2781be75..d114f41863 100644 --- a/src/binary_heap.rs +++ b/src/binary_heap.rs @@ -1,12 +1,12 @@ //! A priority queue implemented with a binary heap. //! -//! Insertion and popping the largest element have `O(log n)` time complexity. Checking the largest -//! / smallest element is `O(1)`. +//! Insertion and popping the largest element have *O*(log n) time complexity. +//! Checking the smallest/largest element is *O*(1). // TODO not yet implemented -// Converting a vector to a binary heap can be done in-place, and has `O(n)` complexity. A binary -// heap can also be converted to a sorted vector in-place, allowing it to be used for an `O(n log -// n)` in-place heapsort. +// Converting a vector to a binary heap can be done in-place, and has *O*(n) complexity. A binary +// heap can also be converted to a sorted vector in-place, allowing it to be used for an +// *O*(n log n) in-place heapsort. use core::{ cmp::Ordering, @@ -97,7 +97,6 @@ impl private::Sealed for Min {} /// // The heap should now be empty. /// assert!(heap.is_empty()) /// ``` - pub struct BinaryHeap { pub(crate) _kind: PhantomData, pub(crate) data: Vec, @@ -337,7 +336,7 @@ where self.sift_up(0, old_len); } - /// Returns the underlying ```Vec```. Order is arbitrary and time is O(1). + /// Returns the underlying `Vec`. Order is arbitrary and time is *O*(1). pub fn into_vec(self) -> Vec { self.data } diff --git a/src/indexmap.rs b/src/indexmap.rs index d3b8a16e55..a6f736cbd2 100644 --- a/src/indexmap.rs +++ b/src/indexmap.rs @@ -12,7 +12,7 @@ use hash32::{BuildHasherDefault, FnvHasher}; use crate::Vec; -/// A [`IndexMap`] using the default FNV hasher +/// An [`IndexMap`] using the default FNV hasher. /// /// A list of all Methods and Traits available for `FnvIndexMap` can be found in /// the [`IndexMap`] documentation. @@ -681,7 +681,7 @@ impl IndexMap { /// Get the first key-value pair /// - /// Computes in **O(1)** time + /// Computes in *O*(1) time pub fn first(&self) -> Option<(&K, &V)> { self.core .entries @@ -691,7 +691,7 @@ impl IndexMap { /// Get the first key-value pair, with mutable access to the value /// - /// Computes in **O(1)** time + /// Computes in *O*(1) time pub fn first_mut(&mut self) -> Option<(&K, &mut V)> { self.core .entries @@ -701,7 +701,7 @@ impl IndexMap { /// Get the last key-value pair /// - /// Computes in **O(1)** time + /// Computes in *O*(1) time pub fn last(&self) -> Option<(&K, &V)> { self.core .entries @@ -711,7 +711,7 @@ impl IndexMap { /// Get the last key-value pair, with mutable access to the value /// - /// Computes in **O(1)** time + /// Computes in *O*(1) time pub fn last_mut(&mut self) -> Option<(&K, &mut V)> { self.core .entries @@ -721,7 +721,7 @@ impl IndexMap { /// Return the number of key-value pairs in the map. /// - /// Computes in **O(1)** time. + /// Computes in *O*(1) time. /// /// ``` /// use heapless::FnvIndexMap; @@ -737,7 +737,7 @@ impl IndexMap { /// Returns true if the map contains no elements. /// - /// Computes in **O(1)** time. + /// Computes in *O*(1) time. /// /// ``` /// use heapless::FnvIndexMap; @@ -753,7 +753,7 @@ impl IndexMap { /// Remove all key-value pairs in the map, while preserving its capacity. /// - /// Computes in **O(n)** time. + /// Computes in *O*(n) time. /// /// ``` /// use heapless::FnvIndexMap; @@ -815,7 +815,7 @@ where /// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed /// form *must* match those for the key type. /// - /// Computes in **O(1)** time (average). + /// Computes in *O*(1) time (average). /// /// ``` /// use heapless::FnvIndexMap; @@ -839,7 +839,7 @@ where /// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed /// form *must* match those for the key type. /// - /// Computes in **O(1)** time (average). + /// Computes in *O*(1) time (average). /// /// # Examples /// @@ -864,7 +864,7 @@ where /// The key may be any borrowed form of the map's key type, but `Hash` and `Eq` on the borrowed /// form *must* match those for the key type. /// - /// Computes in **O(1)** time (average). + /// Computes in *O*(1) time (average). /// /// # Examples /// @@ -899,7 +899,7 @@ where /// If no equivalent key existed in the map: the new key-value pair is inserted, last in order, /// and `None` is returned. /// - /// Computes in **O(1)** time (average). + /// Computes in *O*(1) time (average). /// /// See also entry if you you want to insert or modify or if you need to get the index of the /// corresponding key-value pair. @@ -927,7 +927,7 @@ where /// Same as [`swap_remove`](Self::swap_remove) /// - /// Computes in **O(1)** time (average). + /// Computes in *O*(1) time (average). /// /// # Examples /// @@ -954,7 +954,7 @@ where /// /// Return `None` if `key` is not in map. /// - /// Computes in **O(1)** time (average). + /// Computes in *O*(1) time (average). pub fn swap_remove(&mut self, key: &Q) -> Option where K: Borrow, diff --git a/src/indexset.rs b/src/indexset.rs index 6f072f55fe..404f7e1109 100644 --- a/src/indexset.rs +++ b/src/indexset.rs @@ -7,8 +7,8 @@ use core::{ }; use hash32::{BuildHasherDefault, FnvHasher}; -/// A [`IndexSet`] using the -/// default FNV hasher. +/// An [`IndexSet`] using the default FNV hasher. +/// /// A list of all Methods and Traits available for `FnvIndexSet` can be found in /// the [`IndexSet`] documentation. /// @@ -135,14 +135,14 @@ impl IndexSet { /// Get the first value /// - /// Computes in **O(1)** time + /// Computes in *O*(1) time pub fn first(&self) -> Option<&T> { self.map.first().map(|(k, _v)| k) } /// Get the last value /// - /// Computes in **O(1)** time + /// Computes in *O*(1) time pub fn last(&self) -> Option<&T> { self.map.last().map(|(k, _v)| k) } diff --git a/src/lib.rs b/src/lib.rs index 0d47fe7b3f..333a2d4d0b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ //! Because they have fixed capacity `heapless` data structures don't implicitly reallocate. This //! means that operations like `heapless::Vec.push` are *truly* constant time rather than amortized //! constant time with potentially unbounded (depends on the allocator) worst case execution time -//! (which is bad / unacceptable for hard real time applications). +//! (which is bad/unacceptable for hard real time applications). //! //! `heapless` data structures don't use a memory allocator which means no risk of an uncatchable //! Out Of Memory (OOM) condition while performing operations on them. It's certainly possible to @@ -97,7 +97,7 @@ mod histbuf; mod indexmap; mod indexset; mod linear_map; -mod string; +pub mod string; mod vec; #[cfg(feature = "serde")] diff --git a/src/linear_map.rs b/src/linear_map.rs index e00a818fb8..df5c6a330c 100644 --- a/src/linear_map.rs +++ b/src/linear_map.rs @@ -1,16 +1,16 @@ use crate::Vec; use core::{borrow::Borrow, fmt, iter::FromIterator, mem, ops, slice}; -/// A fixed capacity map / dictionary that performs lookups via linear search +/// A fixed capacity map/dictionary that performs lookups via linear search. /// -/// Note that as this map doesn't use hashing so most operations are **O(N)** instead of O(1) +/// Note that as this map doesn't use hashing so most operations are *O*(n) instead of *O*(1). pub struct LinearMap { pub(crate) buffer: Vec<(K, V), N>, } impl LinearMap { - /// Creates an empty `LinearMap` + /// Creates an empty `LinearMap`. /// /// # Examples /// @@ -32,9 +32,9 @@ impl LinearMap where K: Eq, { - /// Returns the number of elements that the map can hold + /// Returns the number of elements that the map can hold. /// - /// Computes in **O(1)** time + /// Computes in *O*(1) time. /// /// # Examples /// @@ -48,9 +48,9 @@ where N } - /// Clears the map, removing all key-value pairs + /// Clears the map, removing all key-value pairs. /// - /// Computes in **O(1)** time + /// Computes in *O*(1) time. /// /// # Examples /// @@ -68,7 +68,7 @@ where /// Returns true if the map contains a value for the specified key. /// - /// Computes in **O(N)** time + /// Computes in *O*(n) time. /// /// # Examples /// @@ -84,9 +84,9 @@ where self.get(key).is_some() } - /// Returns a reference to the value corresponding to the key + /// Returns a reference to the value corresponding to the key. /// - /// Computes in **O(N)** time + /// Computes in *O*(n) time. /// /// # Examples /// @@ -108,9 +108,9 @@ where .map(|(_, v)| v) } - /// Returns a mutable reference to the value corresponding to the key + /// Returns a mutable reference to the value corresponding to the key. /// - /// Computes in **O(N)** time + /// Computes in *O*(n) time. /// /// # Examples /// @@ -134,9 +134,9 @@ where .map(|(_, v)| v) } - /// Returns the number of elements in this map + /// Returns the number of elements in this map. /// - /// Computes in **O(1)** time + /// Computes in *O*(1) time. /// /// # Examples /// @@ -158,7 +158,7 @@ where /// /// If the map did have this key present, the value is updated, and the old value is returned. /// - /// Computes in **O(N)** time + /// Computes in *O*(n) time /// /// # Examples /// @@ -183,9 +183,9 @@ where Ok(None) } - /// Returns true if the map contains no elements + /// Returns true if the map contains no elements. /// - /// Computes in **O(1)** time + /// Computes in *O*(1) time. /// /// # Examples /// @@ -223,8 +223,8 @@ where } } - /// An iterator visiting all key-value pairs in arbitrary order, with mutable references to the - /// values + /// An iterator visiting all key-value pairs in arbitrary order, + /// with mutable references to the values. /// /// # Examples /// @@ -251,7 +251,7 @@ where } } - /// An iterator visiting all keys in arbitrary order + /// An iterator visiting all keys in arbitrary order. /// /// # Examples /// @@ -271,10 +271,10 @@ where self.iter().map(|(k, _)| k) } - /// Removes a key from the map, returning the value at the key if the key was previously in the - /// map + /// Removes a key from the map, returning the value at + /// the key if the key was previously in the map. /// - /// Computes in **O(N)** time + /// Computes in *O*(n) time /// /// # Examples /// @@ -300,7 +300,7 @@ where idx.map(|idx| self.buffer.swap_remove(idx).1) } - /// An iterator visiting all values in arbitrary order + /// An iterator visiting all values in arbitrary order. /// /// # Examples /// @@ -320,7 +320,7 @@ where self.iter().map(|(_, v)| v) } - /// An iterator visiting all values mutably in arbitrary order + /// An iterator visiting all values mutably in arbitrary order. /// /// # Examples /// diff --git a/src/mpmc.rs b/src/mpmc.rs index e1503d79ec..578a6698b2 100644 --- a/src/mpmc.rs +++ b/src/mpmc.rs @@ -1,4 +1,4 @@ -//! A fixed capacity Multiple-Producer Multiple-Consumer (MPMC) lock-free queue +//! A fixed capacity Multiple-Producer Multiple-Consumer (MPMC) lock-free queue. //! //! NOTE: This module requires atomic CAS operations. On targets where they're not natively available, //! they are emulated by the [`portable-atomic`](https://crates.io/crates/portable-atomic) crate. @@ -6,7 +6,7 @@ //! # Example //! //! This queue can be constructed in "const context". Placing it in a `static` variable lets *all* -//! contexts (interrupts / threads / `main`) safely enqueue and dequeue items from it. +//! contexts (interrupts/threads/`main`) safely enqueue and dequeue items from it. //! //! ``` ignore //! #![no_main] @@ -62,7 +62,7 @@ //! 2|69 |71 | //! //! - `N` denotes the number of *interruptions*. On Cortex-M, an interruption consists of an -//! interrupt handler preempting the would-be atomic section of the `enqueue` / `dequeue` +//! interrupt handler preempting the would-be atomic section of the `enqueue`/`dequeue` //! operation. Note that it does *not* matter if the higher priority handler uses the queue or //! not. //! - All execution times are in clock cycles. 1 clock cycle = 125 ns. diff --git a/src/pool.rs b/src/pool.rs index c5a61829d5..2edc8e6cbf 100644 --- a/src/pool.rs +++ b/src/pool.rs @@ -2,7 +2,7 @@ //! //! # Target support //! -//! This module / API is only available on these compilation targets: +//! This module/API is only available on these compilation targets: //! //! - ARM architectures which instruction set include the LDREX, CLREX and STREX instructions, e.g. //! `thumbv7m-none-eabi` but not `thumbv6m-none-eabi` diff --git a/src/sorted_linked_list.rs b/src/sorted_linked_list.rs index 27f37caeeb..f4102bd065 100644 --- a/src/sorted_linked_list.rs +++ b/src/sorted_linked_list.rs @@ -1,5 +1,6 @@ //! A fixed sorted priority linked list, similar to [`BinaryHeap`] but with different properties //! on `push`, `pop`, etc. +//! //! For example, the sorting of the list will never `memcpy` the underlying value, so having large //! objects in the list will not cause a performance hit. //! @@ -239,7 +240,7 @@ where { /// Pushes a value onto the list without checking if the list is full. /// - /// Complexity is worst-case `O(N)`. + /// Complexity is worst-case *O*(n). /// /// # Safety /// @@ -287,7 +288,7 @@ where /// Pushes an element to the linked list and sorts it into place. /// - /// Complexity is worst-case `O(N)`. + /// Complexity is worst-case *O*(n). /// /// # Example /// @@ -448,7 +449,7 @@ where /// Pops the first element in the list. /// - /// Complexity is worst-case `O(1)`. + /// Complexity is worst-case *O*(1). /// /// # Example /// @@ -584,7 +585,7 @@ where /// This will pop the element from the list. /// - /// Complexity is worst-case `O(1)`. + /// Complexity is worst-case *O*(1). /// /// # Example /// @@ -614,7 +615,7 @@ where /// /// Same as calling `drop`. /// - /// Complexity is worst-case `O(N)`. + /// Complexity is worst-case *O*(n). /// /// # Example /// diff --git a/src/spsc.rs b/src/spsc.rs index 85927ef200..3b9db75f6b 100644 --- a/src/spsc.rs +++ b/src/spsc.rs @@ -1,4 +1,4 @@ -//! Fixed capacity Single Producer Single Consumer (SPSC) queue +//! A fixed capacity Single Producer Single Consumer (SPSC) queue. //! //! Implementation based on //! diff --git a/src/string.rs b/src/string.rs index 01a02521fc..ed378a17b7 100644 --- a/src/string.rs +++ b/src/string.rs @@ -1,6 +1,7 @@ -//! A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html) +//! A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html). use core::{ + char::DecodeUtf16Error, cmp::Ordering, fmt, fmt::{Arguments, Write}, @@ -10,13 +11,35 @@ use core::{ use crate::Vec; -/// A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html) +/// A possible error value when converting a [`String`] from a UTF-16 byte slice. +/// +/// This type is the error type for the [`from_utf16`] method on [`String`]. +/// +/// [`from_utf16`]: String::from_utf16 +#[derive(Debug)] +pub enum FromUtf16Error { + /// The capacity of the `String` is too small for the given operation. + Capacity, + /// Error decoding UTF-16. + DecodeUtf16Error(DecodeUtf16Error), +} + +impl fmt::Display for FromUtf16Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Capacity => "insufficient capacity".fmt(f), + Self::DecodeUtf16Error(e) => write!(f, "invalid UTF-16: {}", e), + } + } +} + +/// A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html). pub struct String { vec: Vec, } impl String { - /// Constructs a new, empty `String` with a fixed capacity of `N` bytes + /// Constructs a new, empty `String` with a fixed capacity of `N` bytes. /// /// # Examples /// @@ -36,6 +59,43 @@ impl String { Self { vec: Vec::new() } } + /// Decodes a UTF-16ā€“encoded slice `v` into a `String`, returning [`Err`] + /// if `v` contains any invalid data. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use heapless::String; + /// + /// // š¯„˛music + /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0x0069, 0x0063]; + /// let s: String<10> = String::from_utf16(v).unwrap(); + /// assert_eq!(s, "š¯„˛music"); + /// + /// // š¯„˛muic + /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075, 0xD800, 0x0069, 0x0063]; + /// assert!(String::<10>::from_utf16(v).is_err()); + /// ``` + #[inline] + pub fn from_utf16(v: &[u16]) -> Result { + let mut s = Self::new(); + + for c in char::decode_utf16(v.iter().cloned()) { + match c { + Ok(c) => { + s.push(c).map_err(|_| FromUtf16Error::Capacity)?; + } + Err(err) => { + return Err(FromUtf16Error::DecodeUtf16Error(err)); + } + } + } + + Ok(s) + } + /// Convert UTF-8 bytes into a `String`. /// /// # Examples @@ -216,7 +276,7 @@ impl String { self.vec.extend_from_slice(string.as_bytes()) } - /// Returns the maximum number of elements the String can hold + /// Returns the maximum number of elements the String can hold. /// /// # Examples /// @@ -334,7 +394,7 @@ impl String { /// Removes a [`char`] from this `String` at a byte position and returns it. /// /// Note: Because this shifts over the remaining elements, it has a - /// worst-case performance of *O*(*n*). + /// worst-case performance of *O*(n). /// /// # Panics /// @@ -586,6 +646,7 @@ impl Ord for String { /// in this case. /// /// [`format!`]: crate::format! +#[doc(hidden)] pub fn format(args: Arguments<'_>) -> Result, fmt::Error> { fn format_inner(args: Arguments<'_>) -> Result, fmt::Error> { let mut output = String::new(); diff --git a/src/vec.rs b/src/vec.rs index 141f1c8358..6d2a7cf692 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -1,6 +1,6 @@ use core::{cmp::Ordering, fmt, hash, iter::FromIterator, mem::MaybeUninit, ops, ptr, slice}; -/// A fixed capacity [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html) +/// A fixed capacity [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html). /// /// # Examples /// @@ -91,7 +91,7 @@ impl Vec { T: Clone, { let mut new = Self::new(); - // avoid `extend_from_slice` as that introduces a runtime check / panicking branch + // avoid `extend_from_slice` as that introduces a runtime check/panicking branch for elem in self { unsafe { new.push_unchecked(elem.clone()); @@ -440,7 +440,7 @@ impl Vec { /// /// The removed element is replaced by the last element of the vector. /// - /// This does not preserve ordering, but is O(1). + /// This does not preserve ordering, but is *O*(1). /// /// # Panics /// @@ -473,7 +473,7 @@ impl Vec { /// /// The removed element is replaced by the last element of the vector. /// - /// This does not preserve ordering, but is O(1). + /// This does not preserve ordering, but is *O*(1). /// /// # Safety /// @@ -620,7 +620,7 @@ impl Vec { /// shifting all elements after it to the left. /// /// Note: Because this shifts over the remaining elements, it has a - /// worst-case performance of *O*(*n*). If you don't need the order of + /// worst-case performance of *O*(n). If you don't need the order of /// elements to be preserved, use [`swap_remove`] instead. If you'd like to /// remove elements from the beginning of the `Vec`, consider using /// [`Deque::pop_front`] instead. @@ -851,7 +851,7 @@ impl fmt::Write for Vec { impl Drop for Vec { fn drop(&mut self) { - // We drop each element used in the vector by turning into a &mut[T] + // We drop each element used in the vector by turning into a `&mut [T]`. unsafe { ptr::drop_in_place(self.as_mut_slice()); }