diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bd1557a..395d95ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- Added `bytes::Buf` and `bytes::BufMut` implementations for `Vec`. - Added `format` macro. - Added `String::from_utf16`. - Added `is_full`, `recent_index`, `oldest`, and `oldest_index` to `HistoryBuffer` diff --git a/Cargo.toml b/Cargo.toml index 8f9ecd04..ec1e4f81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,8 @@ repository = "https://github.com/rust-embedded/heapless" version = "0.8.0" [features] +bytes = ["dep:bytes"] + # Enable polyfilling of atomics via `portable-atomic`. # `portable-atomic` polyfills some functionality by default, but to get full atomics you must # enable one of its features to tell it how to do it. See `portable-atomic` documentation for details. @@ -42,6 +44,7 @@ mpmc_large = [] nightly = [] [dependencies] +bytes = { version = "1", default-features = false, optional = true } portable-atomic = { version = "1.0", optional = true } hash32 = "0.3.0" serde = { version = "1", optional = true, default-features = false } @@ -58,6 +61,7 @@ static_assertions = "1.1.0" [package.metadata.docs.rs] features = [ + "bytes", "ufmt", "serde", "defmt", diff --git a/src/bytes.rs b/src/bytes.rs new file mode 100644 index 00000000..9469be8a --- /dev/null +++ b/src/bytes.rs @@ -0,0 +1,107 @@ +//! Bytes implementations for heapless types + +use crate::Vec; +use bytes::{buf::UninitSlice, Buf, BufMut}; + +unsafe impl Buf for Vec { + #[inline] + fn remaining(&self) -> usize { + self.len() + } + + #[inline] + fn chunk(&mut self) -> &[u8] { + self.as_slice() + } + + #[inline] + unsafe fn advance(&mut self, cnt: usize) { + assert!( + cnt <= self.remaining(), + "cannot advance past `remaining`: {:?} <= {:?}", + cnt, + self.remaining(), + ); + unsafe { + // SAFETY: We've checked that `cnt` <= `self.remaining()` and we know that + // `self.remaining()` <= `self.cap`. + self.advance_unchecked(cnt); + } + } +} + +unsafe impl BufMut for Vec { + #[inline] + fn remaining_mut(&self) -> usize { + N - self.len() + } + + #[inline] + unsafe fn advance_mut(&mut self, cnt: usize) { + let len = self.len(); + let pos = len + cnt; + if pos >= N { + panic!("Advance out of range"); + } + self.set_len(pos); + } + + #[inline] + fn chunk_mut(&mut self) -> &mut UninitSlice { + let len = self.len(); + let ptr = self.as_mut_ptr(); + unsafe { &mut UninitSlice::from_raw_parts_mut(ptr, N)[len..] } + } +} + +#[cfg(test)] +mod tests { + use crate::Vec; + use bytes::BufMut; + + #[test] + #[should_panic] + fn buf_advance_out_of_bounds() { + let mut vec: Vec = Vec::new(); + vec.advance(9) + } + + #[test] + fn buf_remaining() { + let mut vec: Vec = Vec::new(); + assert_eq!(vec.remaining(), 8); + vec.push(42).unwrap(); + assert_eq!(vec.remaining(), 7); + } + + #[test] + fn buf_chunk() { + let mut vec: Vec = Vec::new(); + assert_eq!(vec.chunk().len(), 8); + unsafe { vec.advance_mut(1) }; + assert_eq!(vec.chunk().len(), 7); + } + + #[test] + #[should_panic] + fn buf_mut_advance_mut_out_of_bounds() { + let mut vec: Vec = Vec::new(); + unsafe { vec.advance_mut(9) }; + } + + #[test] + fn buf_mut_remaining_mut() { + let mut vec: Vec = Vec::new(); + assert_eq!(vec.remaining_mut(), 8); + vec.push(42).unwrap(); + assert_eq!(vec.remaining_mut(), 7); + } + + #[test] + fn buf_mut_chunk_mut() { + let mut vec: Vec = Vec::new(); + assert_eq!(vec.chunk_mut().len(), 8); + unsafe { vec.advance_mut(1) }; + assert_eq!(vec.chunk_mut().len(), 7); + } +} diff --git a/src/lib.rs b/src/lib.rs index 37d71413..b7f98693 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -192,6 +192,8 @@ mod de; mod ser; pub mod binary_heap; +#[cfg(feature = "bytes")] +mod bytes; #[cfg(feature = "defmt")] mod defmt; #[cfg(any(