Skip to content

Commit 99ea5f1

Browse files
authored
Merge branch 'master' into write
2 parents 64e8913 + da15496 commit 99ea5f1

File tree

10 files changed

+490
-5
lines changed

10 files changed

+490
-5
lines changed

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
## [v0.5.4] - 2020-04-06
11+
12+
### Added
13+
14+
- Added `StableDeref` implementation for `pool::Box` and `pool::singleton::Box`.
15+
1016
## [v0.5.3] - 2020-01-27
1117

1218
### Added
@@ -288,7 +294,9 @@ architecture.
288294

289295
- Initial release
290296

291-
[Unreleased]: https://github.com/japaric/heapless/compare/v0.5.2...HEAD
297+
[Unreleased]: https://github.com/japaric/heapless/compare/v0.5.4...HEAD
298+
[v0.5.4]: https://github.com/japaric/heapless/compare/v0.5.3...v0.5.4
299+
[v0.5.3]: https://github.com/japaric/heapless/compare/v0.5.2...v0.5.3
292300
[v0.5.2]: https://github.com/japaric/heapless/compare/v0.5.1...v0.5.2
293301
[v0.5.1]: https://github.com/japaric/heapless/compare/v0.5.0...v0.5.1
294302
[v0.5.0]: https://github.com/japaric/heapless/compare/v0.4.4...v0.5.0

Cargo.toml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,12 @@ keywords = [
1717
license = "MIT OR Apache-2.0"
1818
name = "heapless"
1919
repository = "https://github.com/japaric/heapless"
20-
version = "0.5.3"
20+
version = "0.5.4"
2121

2222
[features]
2323
default = ["cas"]
2424
cas = []
25+
ufmt-impl = ["ufmt-write"]
2526
# only for tests
2627
__trybuild = []
2728

@@ -37,3 +38,14 @@ hash32 = "0.1.0"
3738
version = "1"
3839
optional = true
3940
default-features = false
41+
42+
[dependencies.stable_deref_trait]
43+
version = "1"
44+
default-features = false
45+
46+
[dependencies.ufmt-write]
47+
version = "0.1"
48+
optional = true
49+
50+
[dev-dependencies.ufmt]
51+
version = "0.1"

build.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ fn main() -> Result<(), Box<dyn Error>> {
1111
println!("cargo:rustc-cfg=armv7m");
1212
} else if target.starts_with("thumbv7em-") {
1313
println!("cargo:rustc-cfg=armv7m");
14-
} else if target.starts_with("armv7r-") {
14+
} else if target.starts_with("armv7r-") | target.starts_with("armebv7r-") {
1515
println!("cargo:rustc-cfg=armv7r");
1616
} else if target.starts_with("thumbv8m.base") {
1717
println!("cargo:rustc-cfg=armv8m_base");

src/histbuf.rs

Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
use generic_array::{ArrayLength, GenericArray, sequence::GenericSequence};
2+
3+
/// A "history buffer", similar to a write-only ring buffer of fixed length.
4+
///
5+
/// This buffer keeps a fixed number of elements. On write, the oldest element
6+
/// is overwritten. Thus, the buffer is useful to keep a history of values with
7+
/// some desired depth, and for example calculate a rolling average.
8+
///
9+
/// The buffer is always fully initialized; depending on the constructor, the
10+
/// initial value is either the default value for the element type or a supplied
11+
/// initial value. This simplifies the API and is mostly irrelevant for the
12+
/// intended use case.
13+
///
14+
/// # Examples
15+
/// ```
16+
/// use heapless::HistoryBuffer;
17+
/// use heapless::consts::*;
18+
///
19+
/// // Initialize a new buffer with 8 elements, all initially zero.
20+
/// let mut buf = HistoryBuffer::<_, U8>::new();
21+
///
22+
/// buf.write(3);
23+
/// buf.write(5);
24+
/// buf.extend(&[4, 4]);
25+
///
26+
/// // The most recent written element is a four.
27+
/// assert_eq!(buf.recent(), &4);
28+
///
29+
/// // To access all elements in an unspecified order, use `as_slice()`.
30+
/// for el in buf.as_slice() { println!("{:?}", el); }
31+
///
32+
/// // Now we can prepare an average of all values, which comes out to 2.
33+
/// let avg = buf.as_slice().iter().sum::<usize>() / buf.len();
34+
/// assert_eq!(avg, 2);
35+
/// ```
36+
#[derive(Clone)]
37+
pub struct HistoryBuffer<T, N>
38+
where
39+
N: ArrayLength<T>,
40+
{
41+
data: GenericArray<T, N>,
42+
write_at: usize,
43+
}
44+
45+
46+
impl<T, N> HistoryBuffer<T, N>
47+
where
48+
N: ArrayLength<T>,
49+
T: Default,
50+
{
51+
/// Constructs a new history buffer, where every element is filled with the
52+
/// default value of the type `T`.
53+
///
54+
/// `HistoryBuffer` currently cannot be constructed in `const` context.
55+
///
56+
/// # Examples
57+
///
58+
/// ```
59+
/// use heapless::HistoryBuffer;
60+
/// use heapless::consts::*;
61+
///
62+
/// // Allocate a 16-element buffer on the stack
63+
/// let mut x: HistoryBuffer<u8, U16> = HistoryBuffer::new();
64+
/// // All elements are zero
65+
/// assert_eq!(x.as_slice(), [0; 16]);
66+
/// ```
67+
pub fn new() -> Self {
68+
Self {
69+
data: Default::default(),
70+
write_at: 0,
71+
}
72+
}
73+
74+
/// Clears the buffer, replacing every element with the default value of
75+
/// type `T`.
76+
pub fn clear(&mut self) {
77+
*self = Self::new();
78+
}
79+
}
80+
81+
impl<T, N> HistoryBuffer<T, N>
82+
where
83+
N: ArrayLength<T>,
84+
T: Clone,
85+
{
86+
/// Constructs a new history buffer, where every element is the given value.
87+
///
88+
/// # Examples
89+
///
90+
/// ```
91+
/// use heapless::HistoryBuffer;
92+
/// use heapless::consts::*;
93+
///
94+
/// // Allocate a 16-element buffer on the stack
95+
/// let mut x: HistoryBuffer<u8, U16> = HistoryBuffer::new_with(4);
96+
/// // All elements are four
97+
/// assert_eq!(x.as_slice(), [4; 16]);
98+
/// ```
99+
pub fn new_with(t: T) -> Self {
100+
Self {
101+
data: GenericArray::generate(|_| t.clone()),
102+
write_at: 0,
103+
}
104+
}
105+
106+
/// Clears the buffer, replacing every element with the given value.
107+
pub fn clear_with(&mut self, t: T) {
108+
*self = Self::new_with(t);
109+
}
110+
}
111+
112+
impl<T, N> HistoryBuffer<T, N>
113+
where
114+
N: ArrayLength<T>,
115+
{
116+
/// Returns the capacity of the buffer, which is the length of the
117+
/// underlying backing array.
118+
pub fn len(&self) -> usize {
119+
self.data.len()
120+
}
121+
122+
/// Writes an element to the buffer, overwriting the oldest value.
123+
pub fn write(&mut self, t: T) {
124+
self.data[self.write_at] = t;
125+
self.write_at = (self.write_at + 1) % self.len();
126+
}
127+
128+
/// Clones and writes all elements in a slice to the buffer.
129+
///
130+
/// If the slice is longer than the buffer, only the last `self.len()`
131+
/// elements will actually be stored.
132+
pub fn extend_from_slice(&mut self, other: &[T])
133+
where
134+
T: Clone,
135+
{
136+
for item in other {
137+
self.write(item.clone());
138+
}
139+
}
140+
141+
/// Returns a reference to the most recently written value.
142+
///
143+
/// # Examples
144+
///
145+
/// ```
146+
/// use heapless::HistoryBuffer;
147+
/// use heapless::consts::*;
148+
///
149+
/// let mut x: HistoryBuffer<u8, U16> = HistoryBuffer::new();
150+
/// x.write(4);
151+
/// x.write(10);
152+
/// assert_eq!(x.recent(), &10);
153+
/// ```
154+
pub fn recent(&self) -> &T {
155+
&self.data[(self.write_at + self.len() - 1) % self.len()]
156+
}
157+
158+
/// Returns the array slice backing the buffer, without keeping track
159+
/// of the write position. Therefore, the element order is unspecified.
160+
pub fn as_slice(&self) -> &[T] {
161+
&self.data
162+
}
163+
}
164+
165+
impl<T, N> Extend<T> for HistoryBuffer<T, N>
166+
where
167+
N: ArrayLength<T>,
168+
{
169+
fn extend<I>(&mut self, iter: I)
170+
where
171+
I: IntoIterator<Item = T>,
172+
{
173+
for item in iter.into_iter() {
174+
self.write(item);
175+
}
176+
}
177+
}
178+
179+
impl<'a, T, N> Extend<&'a T> for HistoryBuffer<T, N>
180+
where
181+
T: 'a + Clone,
182+
N: ArrayLength<T>,
183+
{
184+
fn extend<I>(&mut self, iter: I)
185+
where
186+
I: IntoIterator<Item = &'a T>,
187+
{
188+
self.extend(iter.into_iter().cloned())
189+
}
190+
}
191+
192+
#[cfg(test)]
193+
mod tests {
194+
use crate::{consts::*, HistoryBuffer};
195+
196+
#[test]
197+
fn new() {
198+
let x: HistoryBuffer<u8, U4> = HistoryBuffer::new_with(1);
199+
assert_eq!(x.len(), 4);
200+
assert_eq!(x.as_slice(), [1; 4]);
201+
202+
let x: HistoryBuffer<u8, U4> = HistoryBuffer::new();
203+
assert_eq!(x.as_slice(), [0; 4]);
204+
}
205+
206+
#[test]
207+
fn write() {
208+
let mut x: HistoryBuffer<u8, U4> = HistoryBuffer::new();
209+
x.write(1);
210+
x.write(4);
211+
assert_eq!(x.as_slice(), [1, 4, 0, 0]);
212+
213+
x.write(5);
214+
x.write(6);
215+
x.write(10);
216+
assert_eq!(x.as_slice(), [10, 4, 5, 6]);
217+
218+
x.extend([11, 12].iter());
219+
assert_eq!(x.as_slice(), [10, 11, 12, 6]);
220+
}
221+
222+
#[test]
223+
fn clear() {
224+
let mut x: HistoryBuffer<u8, U4> = HistoryBuffer::new_with(1);
225+
x.clear();
226+
assert_eq!(x.as_slice(), [0; 4]);
227+
228+
let mut x: HistoryBuffer<u8, U4> = HistoryBuffer::new();
229+
x.clear_with(1);
230+
assert_eq!(x.as_slice(), [1; 4]);
231+
}
232+
233+
#[test]
234+
fn recent() {
235+
let mut x: HistoryBuffer<u8, U4> = HistoryBuffer::new();
236+
assert_eq!(x.recent(), &0);
237+
238+
x.write(1);
239+
x.write(4);
240+
assert_eq!(x.recent(), &4);
241+
242+
x.write(5);
243+
x.write(6);
244+
x.write(10);
245+
assert_eq!(x.recent(), &10);
246+
}
247+
248+
#[test]
249+
fn as_slice() {
250+
let mut x: HistoryBuffer<u8, U4> = HistoryBuffer::new();
251+
252+
x.extend([1, 2, 3, 4, 5].iter());
253+
254+
assert_eq!(x.as_slice(), [5, 2, 3, 4]);
255+
}
256+
}

src/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,14 @@
5656
//! - [`mpmc::Q*`](mpmc/index.html) -- multiple producer multiple consumer lock-free queue
5757
//! - [`spsc::Queue`](spsc/struct.Queue.html) -- single producer single consumer lock-free queue
5858
//!
59+
//! # Optional Features
60+
//!
61+
//! The `heapless` crate provides the following optional Cargo features:
62+
//!
63+
//! - `ufmt-impl`: Implement [`ufmt_write::uWrite`] for `String<N>` and `Vec<u8, N>`
64+
//!
65+
//! [`ufmt_write::uWrite`]: https://docs.rs/ufmt-write/
66+
//!
5967
//! # Minimum Supported Rust Version (MSRV)
6068
//!
6169
//! This crate is guaranteed to compile on stable Rust 1.36 and up with its default set of features.
@@ -75,13 +83,15 @@ pub use indexset::{FnvIndexSet, IndexSet};
7583
pub use linear_map::LinearMap;
7684
pub use string::String;
7785
pub use vec::Vec;
86+
pub use histbuf::HistoryBuffer;
7887

7988
// NOTE this code was last ported from v0.4.1 of the indexmap crate
8089
mod indexmap;
8190
mod indexset;
8291
mod linear_map;
8392
mod string;
8493
mod vec;
94+
mod histbuf;
8595

8696
#[cfg(feature = "serde")]
8797
mod de;
@@ -97,4 +107,7 @@ pub mod pool;
97107
#[cfg(has_atomics)]
98108
pub mod spsc;
99109

110+
#[cfg(feature = "ufmt-impl")]
111+
mod ufmt;
112+
100113
mod sealed;

src/pool/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,8 @@ unsafe impl<T, S> Send for Box<T, S> where T: Send {}
375375

376376
unsafe impl<T, S> Sync for Box<T, S> where T: Sync {}
377377

378+
unsafe impl<T> stable_deref_trait::StableDeref for Box<T> {}
379+
378380
impl<A> AsSlice for Box<A>
379381
where
380382
A: AsSlice,

src/pool/singleton.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,8 @@ where
160160
}
161161
}
162162

163+
unsafe impl<P: Pool> stable_deref_trait::StableDeref for Box<P> {}
164+
163165
impl<P> fmt::Debug for Box<P>
164166
where
165167
P: Pool,

0 commit comments

Comments
 (0)