mirror of
https://github.com/rust-embedded/heapless.git
synced 2025-10-02 23:04:40 +00:00
Merge branch 'master' into write
This commit is contained in:
commit
99ea5f123e
10
CHANGELOG.md
10
CHANGELOG.md
@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [v0.5.4] - 2020-04-06
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added `StableDeref` implementation for `pool::Box` and `pool::singleton::Box`.
|
||||||
|
|
||||||
## [v0.5.3] - 2020-01-27
|
## [v0.5.3] - 2020-01-27
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
@ -288,7 +294,9 @@ architecture.
|
|||||||
|
|
||||||
- Initial release
|
- Initial release
|
||||||
|
|
||||||
[Unreleased]: https://github.com/japaric/heapless/compare/v0.5.2...HEAD
|
[Unreleased]: https://github.com/japaric/heapless/compare/v0.5.4...HEAD
|
||||||
|
[v0.5.4]: https://github.com/japaric/heapless/compare/v0.5.3...v0.5.4
|
||||||
|
[v0.5.3]: https://github.com/japaric/heapless/compare/v0.5.2...v0.5.3
|
||||||
[v0.5.2]: https://github.com/japaric/heapless/compare/v0.5.1...v0.5.2
|
[v0.5.2]: https://github.com/japaric/heapless/compare/v0.5.1...v0.5.2
|
||||||
[v0.5.1]: https://github.com/japaric/heapless/compare/v0.5.0...v0.5.1
|
[v0.5.1]: https://github.com/japaric/heapless/compare/v0.5.0...v0.5.1
|
||||||
[v0.5.0]: https://github.com/japaric/heapless/compare/v0.4.4...v0.5.0
|
[v0.5.0]: https://github.com/japaric/heapless/compare/v0.4.4...v0.5.0
|
||||||
|
14
Cargo.toml
14
Cargo.toml
@ -17,11 +17,12 @@ keywords = [
|
|||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
name = "heapless"
|
name = "heapless"
|
||||||
repository = "https://github.com/japaric/heapless"
|
repository = "https://github.com/japaric/heapless"
|
||||||
version = "0.5.3"
|
version = "0.5.4"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["cas"]
|
default = ["cas"]
|
||||||
cas = []
|
cas = []
|
||||||
|
ufmt-impl = ["ufmt-write"]
|
||||||
# only for tests
|
# only for tests
|
||||||
__trybuild = []
|
__trybuild = []
|
||||||
|
|
||||||
@ -37,3 +38,14 @@ hash32 = "0.1.0"
|
|||||||
version = "1"
|
version = "1"
|
||||||
optional = true
|
optional = true
|
||||||
default-features = false
|
default-features = false
|
||||||
|
|
||||||
|
[dependencies.stable_deref_trait]
|
||||||
|
version = "1"
|
||||||
|
default-features = false
|
||||||
|
|
||||||
|
[dependencies.ufmt-write]
|
||||||
|
version = "0.1"
|
||||||
|
optional = true
|
||||||
|
|
||||||
|
[dev-dependencies.ufmt]
|
||||||
|
version = "0.1"
|
||||||
|
2
build.rs
2
build.rs
@ -11,7 +11,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
println!("cargo:rustc-cfg=armv7m");
|
println!("cargo:rustc-cfg=armv7m");
|
||||||
} else if target.starts_with("thumbv7em-") {
|
} else if target.starts_with("thumbv7em-") {
|
||||||
println!("cargo:rustc-cfg=armv7m");
|
println!("cargo:rustc-cfg=armv7m");
|
||||||
} else if target.starts_with("armv7r-") {
|
} else if target.starts_with("armv7r-") | target.starts_with("armebv7r-") {
|
||||||
println!("cargo:rustc-cfg=armv7r");
|
println!("cargo:rustc-cfg=armv7r");
|
||||||
} else if target.starts_with("thumbv8m.base") {
|
} else if target.starts_with("thumbv8m.base") {
|
||||||
println!("cargo:rustc-cfg=armv8m_base");
|
println!("cargo:rustc-cfg=armv8m_base");
|
||||||
|
256
src/histbuf.rs
Normal file
256
src/histbuf.rs
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
use generic_array::{ArrayLength, GenericArray, sequence::GenericSequence};
|
||||||
|
|
||||||
|
/// A "history buffer", similar to a write-only ring buffer of fixed length.
|
||||||
|
///
|
||||||
|
/// This buffer keeps a fixed number of elements. On write, the oldest element
|
||||||
|
/// is overwritten. Thus, the buffer is useful to keep a history of values with
|
||||||
|
/// some desired depth, and for example calculate a rolling average.
|
||||||
|
///
|
||||||
|
/// The buffer is always fully initialized; depending on the constructor, the
|
||||||
|
/// initial value is either the default value for the element type or a supplied
|
||||||
|
/// initial value. This simplifies the API and is mostly irrelevant for the
|
||||||
|
/// intended use case.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
/// ```
|
||||||
|
/// use heapless::HistoryBuffer;
|
||||||
|
/// use heapless::consts::*;
|
||||||
|
///
|
||||||
|
/// // Initialize a new buffer with 8 elements, all initially zero.
|
||||||
|
/// let mut buf = HistoryBuffer::<_, U8>::new();
|
||||||
|
///
|
||||||
|
/// buf.write(3);
|
||||||
|
/// buf.write(5);
|
||||||
|
/// buf.extend(&[4, 4]);
|
||||||
|
///
|
||||||
|
/// // The most recent written element is a four.
|
||||||
|
/// assert_eq!(buf.recent(), &4);
|
||||||
|
///
|
||||||
|
/// // To access all elements in an unspecified order, use `as_slice()`.
|
||||||
|
/// for el in buf.as_slice() { println!("{:?}", el); }
|
||||||
|
///
|
||||||
|
/// // Now we can prepare an average of all values, which comes out to 2.
|
||||||
|
/// let avg = buf.as_slice().iter().sum::<usize>() / buf.len();
|
||||||
|
/// assert_eq!(avg, 2);
|
||||||
|
/// ```
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct HistoryBuffer<T, N>
|
||||||
|
where
|
||||||
|
N: ArrayLength<T>,
|
||||||
|
{
|
||||||
|
data: GenericArray<T, N>,
|
||||||
|
write_at: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<T, N> HistoryBuffer<T, N>
|
||||||
|
where
|
||||||
|
N: ArrayLength<T>,
|
||||||
|
T: Default,
|
||||||
|
{
|
||||||
|
/// Constructs a new history buffer, where every element is filled with the
|
||||||
|
/// default value of the type `T`.
|
||||||
|
///
|
||||||
|
/// `HistoryBuffer` currently cannot be constructed in `const` context.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heapless::HistoryBuffer;
|
||||||
|
/// use heapless::consts::*;
|
||||||
|
///
|
||||||
|
/// // Allocate a 16-element buffer on the stack
|
||||||
|
/// let mut x: HistoryBuffer<u8, U16> = HistoryBuffer::new();
|
||||||
|
/// // All elements are zero
|
||||||
|
/// assert_eq!(x.as_slice(), [0; 16]);
|
||||||
|
/// ```
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
data: Default::default(),
|
||||||
|
write_at: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the buffer, replacing every element with the default value of
|
||||||
|
/// type `T`.
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
*self = Self::new();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, N> HistoryBuffer<T, N>
|
||||||
|
where
|
||||||
|
N: ArrayLength<T>,
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
/// Constructs a new history buffer, where every element is the given value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heapless::HistoryBuffer;
|
||||||
|
/// use heapless::consts::*;
|
||||||
|
///
|
||||||
|
/// // Allocate a 16-element buffer on the stack
|
||||||
|
/// let mut x: HistoryBuffer<u8, U16> = HistoryBuffer::new_with(4);
|
||||||
|
/// // All elements are four
|
||||||
|
/// assert_eq!(x.as_slice(), [4; 16]);
|
||||||
|
/// ```
|
||||||
|
pub fn new_with(t: T) -> Self {
|
||||||
|
Self {
|
||||||
|
data: GenericArray::generate(|_| t.clone()),
|
||||||
|
write_at: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the buffer, replacing every element with the given value.
|
||||||
|
pub fn clear_with(&mut self, t: T) {
|
||||||
|
*self = Self::new_with(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, N> HistoryBuffer<T, N>
|
||||||
|
where
|
||||||
|
N: ArrayLength<T>,
|
||||||
|
{
|
||||||
|
/// Returns the capacity of the buffer, which is the length of the
|
||||||
|
/// underlying backing array.
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.data.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Writes an element to the buffer, overwriting the oldest value.
|
||||||
|
pub fn write(&mut self, t: T) {
|
||||||
|
self.data[self.write_at] = t;
|
||||||
|
self.write_at = (self.write_at + 1) % self.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clones and writes all elements in a slice to the buffer.
|
||||||
|
///
|
||||||
|
/// If the slice is longer than the buffer, only the last `self.len()`
|
||||||
|
/// elements will actually be stored.
|
||||||
|
pub fn extend_from_slice(&mut self, other: &[T])
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
for item in other {
|
||||||
|
self.write(item.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the most recently written value.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heapless::HistoryBuffer;
|
||||||
|
/// use heapless::consts::*;
|
||||||
|
///
|
||||||
|
/// let mut x: HistoryBuffer<u8, U16> = HistoryBuffer::new();
|
||||||
|
/// x.write(4);
|
||||||
|
/// x.write(10);
|
||||||
|
/// assert_eq!(x.recent(), &10);
|
||||||
|
/// ```
|
||||||
|
pub fn recent(&self) -> &T {
|
||||||
|
&self.data[(self.write_at + self.len() - 1) % self.len()]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the array slice backing the buffer, without keeping track
|
||||||
|
/// of the write position. Therefore, the element order is unspecified.
|
||||||
|
pub fn as_slice(&self) -> &[T] {
|
||||||
|
&self.data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, N> Extend<T> for HistoryBuffer<T, N>
|
||||||
|
where
|
||||||
|
N: ArrayLength<T>,
|
||||||
|
{
|
||||||
|
fn extend<I>(&mut self, iter: I)
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = T>,
|
||||||
|
{
|
||||||
|
for item in iter.into_iter() {
|
||||||
|
self.write(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T, N> Extend<&'a T> for HistoryBuffer<T, N>
|
||||||
|
where
|
||||||
|
T: 'a + Clone,
|
||||||
|
N: ArrayLength<T>,
|
||||||
|
{
|
||||||
|
fn extend<I>(&mut self, iter: I)
|
||||||
|
where
|
||||||
|
I: IntoIterator<Item = &'a T>,
|
||||||
|
{
|
||||||
|
self.extend(iter.into_iter().cloned())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::{consts::*, HistoryBuffer};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn new() {
|
||||||
|
let x: HistoryBuffer<u8, U4> = HistoryBuffer::new_with(1);
|
||||||
|
assert_eq!(x.len(), 4);
|
||||||
|
assert_eq!(x.as_slice(), [1; 4]);
|
||||||
|
|
||||||
|
let x: HistoryBuffer<u8, U4> = HistoryBuffer::new();
|
||||||
|
assert_eq!(x.as_slice(), [0; 4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn write() {
|
||||||
|
let mut x: HistoryBuffer<u8, U4> = HistoryBuffer::new();
|
||||||
|
x.write(1);
|
||||||
|
x.write(4);
|
||||||
|
assert_eq!(x.as_slice(), [1, 4, 0, 0]);
|
||||||
|
|
||||||
|
x.write(5);
|
||||||
|
x.write(6);
|
||||||
|
x.write(10);
|
||||||
|
assert_eq!(x.as_slice(), [10, 4, 5, 6]);
|
||||||
|
|
||||||
|
x.extend([11, 12].iter());
|
||||||
|
assert_eq!(x.as_slice(), [10, 11, 12, 6]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn clear() {
|
||||||
|
let mut x: HistoryBuffer<u8, U4> = HistoryBuffer::new_with(1);
|
||||||
|
x.clear();
|
||||||
|
assert_eq!(x.as_slice(), [0; 4]);
|
||||||
|
|
||||||
|
let mut x: HistoryBuffer<u8, U4> = HistoryBuffer::new();
|
||||||
|
x.clear_with(1);
|
||||||
|
assert_eq!(x.as_slice(), [1; 4]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn recent() {
|
||||||
|
let mut x: HistoryBuffer<u8, U4> = HistoryBuffer::new();
|
||||||
|
assert_eq!(x.recent(), &0);
|
||||||
|
|
||||||
|
x.write(1);
|
||||||
|
x.write(4);
|
||||||
|
assert_eq!(x.recent(), &4);
|
||||||
|
|
||||||
|
x.write(5);
|
||||||
|
x.write(6);
|
||||||
|
x.write(10);
|
||||||
|
assert_eq!(x.recent(), &10);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn as_slice() {
|
||||||
|
let mut x: HistoryBuffer<u8, U4> = HistoryBuffer::new();
|
||||||
|
|
||||||
|
x.extend([1, 2, 3, 4, 5].iter());
|
||||||
|
|
||||||
|
assert_eq!(x.as_slice(), [5, 2, 3, 4]);
|
||||||
|
}
|
||||||
|
}
|
13
src/lib.rs
13
src/lib.rs
@ -56,6 +56,14 @@
|
|||||||
//! - [`mpmc::Q*`](mpmc/index.html) -- multiple producer multiple consumer lock-free queue
|
//! - [`mpmc::Q*`](mpmc/index.html) -- multiple producer multiple consumer lock-free queue
|
||||||
//! - [`spsc::Queue`](spsc/struct.Queue.html) -- single producer single consumer lock-free queue
|
//! - [`spsc::Queue`](spsc/struct.Queue.html) -- single producer single consumer lock-free queue
|
||||||
//!
|
//!
|
||||||
|
//! # Optional Features
|
||||||
|
//!
|
||||||
|
//! The `heapless` crate provides the following optional Cargo features:
|
||||||
|
//!
|
||||||
|
//! - `ufmt-impl`: Implement [`ufmt_write::uWrite`] for `String<N>` and `Vec<u8, N>`
|
||||||
|
//!
|
||||||
|
//! [`ufmt_write::uWrite`]: https://docs.rs/ufmt-write/
|
||||||
|
//!
|
||||||
//! # Minimum Supported Rust Version (MSRV)
|
//! # Minimum Supported Rust Version (MSRV)
|
||||||
//!
|
//!
|
||||||
//! This crate is guaranteed to compile on stable Rust 1.36 and up with its default set of features.
|
//! This crate is guaranteed to compile on stable Rust 1.36 and up with its default set of features.
|
||||||
@ -75,6 +83,7 @@ pub use indexset::{FnvIndexSet, IndexSet};
|
|||||||
pub use linear_map::LinearMap;
|
pub use linear_map::LinearMap;
|
||||||
pub use string::String;
|
pub use string::String;
|
||||||
pub use vec::Vec;
|
pub use vec::Vec;
|
||||||
|
pub use histbuf::HistoryBuffer;
|
||||||
|
|
||||||
// NOTE this code was last ported from v0.4.1 of the indexmap crate
|
// NOTE this code was last ported from v0.4.1 of the indexmap crate
|
||||||
mod indexmap;
|
mod indexmap;
|
||||||
@ -82,6 +91,7 @@ mod indexset;
|
|||||||
mod linear_map;
|
mod linear_map;
|
||||||
mod string;
|
mod string;
|
||||||
mod vec;
|
mod vec;
|
||||||
|
mod histbuf;
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
mod de;
|
mod de;
|
||||||
@ -97,4 +107,7 @@ pub mod pool;
|
|||||||
#[cfg(has_atomics)]
|
#[cfg(has_atomics)]
|
||||||
pub mod spsc;
|
pub mod spsc;
|
||||||
|
|
||||||
|
#[cfg(feature = "ufmt-impl")]
|
||||||
|
mod ufmt;
|
||||||
|
|
||||||
mod sealed;
|
mod sealed;
|
||||||
|
@ -375,6 +375,8 @@ unsafe impl<T, S> Send for Box<T, S> where T: Send {}
|
|||||||
|
|
||||||
unsafe impl<T, S> Sync for Box<T, S> where T: Sync {}
|
unsafe impl<T, S> Sync for Box<T, S> where T: Sync {}
|
||||||
|
|
||||||
|
unsafe impl<T> stable_deref_trait::StableDeref for Box<T> {}
|
||||||
|
|
||||||
impl<A> AsSlice for Box<A>
|
impl<A> AsSlice for Box<A>
|
||||||
where
|
where
|
||||||
A: AsSlice,
|
A: AsSlice,
|
||||||
|
@ -160,6 +160,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl<P: Pool> stable_deref_trait::StableDeref for Box<P> {}
|
||||||
|
|
||||||
impl<P> fmt::Debug for Box<P>
|
impl<P> fmt::Debug for Box<P>
|
||||||
where
|
where
|
||||||
P: Pool,
|
P: Pool,
|
||||||
|
71
src/ufmt.rs
Normal file
71
src/ufmt.rs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
use ufmt_write::uWrite;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ArrayLength,
|
||||||
|
string::String,
|
||||||
|
vec::Vec,
|
||||||
|
};
|
||||||
|
|
||||||
|
impl<N> uWrite for String<N>
|
||||||
|
where
|
||||||
|
N: ArrayLength<u8>,
|
||||||
|
{
|
||||||
|
type Error = ();
|
||||||
|
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
|
||||||
|
self.push_str(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N> uWrite for Vec<u8, N>
|
||||||
|
where
|
||||||
|
N: ArrayLength<u8>,
|
||||||
|
{
|
||||||
|
type Error = ();
|
||||||
|
fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
|
||||||
|
self.extend_from_slice(s.as_bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use ufmt::{derive::uDebug, uwrite};
|
||||||
|
|
||||||
|
use crate::consts::*;
|
||||||
|
|
||||||
|
#[derive(uDebug)]
|
||||||
|
struct Pair {
|
||||||
|
x: u32,
|
||||||
|
y: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_string() {
|
||||||
|
let a = 123;
|
||||||
|
let b = Pair { x: 0, y: 1234 };
|
||||||
|
|
||||||
|
let mut s = String::<U32>::new();
|
||||||
|
uwrite!(s, "{} -> {:?}", a, b).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(s, "123 -> Pair { x: 0, y: 1234 }");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_string_err() {
|
||||||
|
let p = Pair { x: 0, y: 1234 };
|
||||||
|
let mut s = String::<U4>::new();
|
||||||
|
assert!(uwrite!(s, "{:?}", p).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vec() {
|
||||||
|
let a = 123;
|
||||||
|
let b = Pair { x: 0, y: 1234 };
|
||||||
|
|
||||||
|
let mut v = Vec::<u8, U32>::new();
|
||||||
|
uwrite!(v, "{} -> {:?}", a, b).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(v, b"123 -> Pair { x: 0, y: 1234 }");
|
||||||
|
}
|
||||||
|
}
|
122
src/vec.rs
122
src/vec.rs
@ -197,6 +197,28 @@ where
|
|||||||
Vec(crate::i::Vec::new())
|
Vec(crate::i::Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constructs a new vector with a fixed capacity of `N` and fills it
|
||||||
|
/// with the provided slice.
|
||||||
|
///
|
||||||
|
/// This is equivalent to the following code:
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heapless::Vec;
|
||||||
|
/// use heapless::consts::*;
|
||||||
|
///
|
||||||
|
/// let mut v: Vec<u8, U16> = Vec::new();
|
||||||
|
/// v.extend_from_slice(&[1, 2, 3]).unwrap();
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn from_slice(other: &[T]) -> Result<Self, ()>
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
let mut v = Vec::new();
|
||||||
|
v.extend_from_slice(other)?;
|
||||||
|
Ok(v)
|
||||||
|
}
|
||||||
|
|
||||||
/* Public API */
|
/* Public API */
|
||||||
/// Returns the maximum number of elements the vector can hold
|
/// Returns the maximum number of elements the vector can hold
|
||||||
pub fn capacity(&self) -> usize {
|
pub fn capacity(&self) -> usize {
|
||||||
@ -344,6 +366,54 @@ where
|
|||||||
pub(crate) fn is_full(&self) -> bool {
|
pub(crate) fn is_full(&self) -> bool {
|
||||||
self.0.is_full()
|
self.0.is_full()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if `needle` is a prefix of the Vec.
|
||||||
|
///
|
||||||
|
/// Always returns `true` if `needle` is an empty slice.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heapless::Vec;
|
||||||
|
/// use heapless::consts::*;
|
||||||
|
///
|
||||||
|
/// let v: Vec<_, U8> = Vec::from_slice(b"abc").unwrap();
|
||||||
|
/// assert_eq!(v.starts_with(b""), true);
|
||||||
|
/// assert_eq!(v.starts_with(b"ab"), true);
|
||||||
|
/// assert_eq!(v.starts_with(b"bc"), false);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn starts_with(&self, needle: &[T]) -> bool
|
||||||
|
where
|
||||||
|
T: PartialEq,
|
||||||
|
{
|
||||||
|
let n = needle.len();
|
||||||
|
self.len() >= n && needle == &self[..n]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if `needle` is a suffix of the Vec.
|
||||||
|
///
|
||||||
|
/// Always returns `true` if `needle` is an empty slice.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use heapless::Vec;
|
||||||
|
/// use heapless::consts::*;
|
||||||
|
///
|
||||||
|
/// let v: Vec<_, U8> = Vec::from_slice(b"abc").unwrap();
|
||||||
|
/// assert_eq!(v.ends_with(b""), true);
|
||||||
|
/// assert_eq!(v.ends_with(b"ab"), false);
|
||||||
|
/// assert_eq!(v.ends_with(b"bc"), true);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
pub fn ends_with(&self, needle: &[T]) -> bool
|
||||||
|
where
|
||||||
|
T: PartialEq,
|
||||||
|
{
|
||||||
|
let (v, n) = (self.len(), needle.len());
|
||||||
|
v >= n && needle == &self[v - n..]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, N> Default for Vec<T, N>
|
impl<T, N> Default for Vec<T, N>
|
||||||
@ -656,6 +726,7 @@ where
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use as_slice::AsSlice;
|
||||||
use crate::{consts::*, Vec};
|
use crate::{consts::*, Vec};
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
|
|
||||||
@ -929,6 +1000,55 @@ mod tests {
|
|||||||
fn write() {
|
fn write() {
|
||||||
let mut v: Vec<u8, U4> = Vec::new();
|
let mut v: Vec<u8, U4> = Vec::new();
|
||||||
write!(v, "{:x}", 1234).unwrap();
|
write!(v, "{:x}", 1234).unwrap();
|
||||||
assert_eq!(&v[..], b"4d2")
|
assert_eq!(&v[..], b"4d2");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extend_from_slice() {
|
||||||
|
let mut v: Vec<u8, U4> = Vec::new();
|
||||||
|
assert_eq!(v.len(), 0);
|
||||||
|
v.extend_from_slice(&[1, 2]).unwrap();
|
||||||
|
assert_eq!(v.len(), 2);
|
||||||
|
assert_eq!(v.as_slice(), &[1, 2]);
|
||||||
|
v.extend_from_slice(&[3]).unwrap();
|
||||||
|
assert_eq!(v.len(), 3);
|
||||||
|
assert_eq!(v.as_slice(), &[1, 2, 3]);
|
||||||
|
assert!(v.extend_from_slice(&[4, 5]).is_err());
|
||||||
|
assert_eq!(v.len(), 3);
|
||||||
|
assert_eq!(v.as_slice(), &[1, 2, 3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn from_slice() {
|
||||||
|
// Successful construction
|
||||||
|
let v: Vec<u8, U4> = Vec::from_slice(&[1, 2, 3]).unwrap();
|
||||||
|
assert_eq!(v.len(), 3);
|
||||||
|
assert_eq!(v.as_slice(), &[1, 2, 3]);
|
||||||
|
|
||||||
|
// Slice too large
|
||||||
|
assert!(Vec::<u8, U2>::from_slice(&[1, 2, 3]).is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn starts_with() {
|
||||||
|
let v: Vec<_, U8> = Vec::from_slice(b"ab").unwrap();
|
||||||
|
assert!(v.starts_with(&[]));
|
||||||
|
assert!(v.starts_with(b""));
|
||||||
|
assert!(v.starts_with(b"a"));
|
||||||
|
assert!(v.starts_with(b"ab"));
|
||||||
|
assert!(!v.starts_with(b"abc"));
|
||||||
|
assert!(!v.starts_with(b"ba"));
|
||||||
|
assert!(!v.starts_with(b"b"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ends_with() {
|
||||||
|
let v: Vec<_, U8> = Vec::from_slice(b"ab").unwrap();
|
||||||
|
assert!(v.ends_with(&[]));
|
||||||
|
assert!(v.ends_with(b""));
|
||||||
|
assert!(v.ends_with(b"b"));
|
||||||
|
assert!(v.ends_with(b"ab"));
|
||||||
|
assert!(!v.ends_with(b"abc"));
|
||||||
|
assert!(!v.ends_with(b"ba"));
|
||||||
|
assert!(!v.ends_with(b"a"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
use heapless::{
|
use heapless::{
|
||||||
consts,
|
consts,
|
||||||
spsc::{Consumer, Producer, Queue},
|
spsc::{Consumer, Producer, Queue},
|
||||||
Vec,
|
Vec, HistoryBuffer,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -22,4 +22,5 @@ fn send() {
|
|||||||
is_send::<Producer<IsSend, consts::U4>>();
|
is_send::<Producer<IsSend, consts::U4>>();
|
||||||
is_send::<Queue<IsSend, consts::U4>>();
|
is_send::<Queue<IsSend, consts::U4>>();
|
||||||
is_send::<Vec<IsSend, consts::U4>>();
|
is_send::<Vec<IsSend, consts::U4>>();
|
||||||
|
is_send::<HistoryBuffer<IsSend, consts::U4>>();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user