Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .rustfmt.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
imports_granularity = "Crate"
comment_width = 100
wrap_comments = true
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ $ # run only for example histbuf tests
$ cargo test histbuf --features serde
```

# Formatting

Like most Rust projects, we use `rustfmt` to keep the formatting of code consistent. However, we
make use of cecertain options that are currently only available in the nightly version:

```console
$ cargo +nightly fmt --all
```

## License

Licensed under either of
Expand Down
14 changes: 8 additions & 6 deletions src/c_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,12 @@ impl<const N: usize, LenT: LenType> CString<N, LenT> {
///
/// # Safety
///
/// - The memory pointed to by `ptr` must contain a valid nul terminator at the
/// end of the string.
/// - `ptr` must be valid for reads of bytes up to and including the nul terminator.
/// This means in particular:
/// - The entire memory range of this `CStr` must be contained within a single allocated object!
/// - The memory pointed to by `ptr` must contain a valid nul terminator at the end of the
/// string.
/// - `ptr` must be valid for reads of bytes up to and including the nul terminator. This means
/// in particular:
/// - The entire memory range of this `CStr` must be contained within a single allocated
/// object!
/// - `ptr` must be non-nul even for a zero-length `CStr`.
///
/// # Example
Expand Down Expand Up @@ -190,7 +191,8 @@ impl<const N: usize, LenT: LenType> CString<N, LenT> {

match CStr::from_bytes_with_nul(bytes) {
Ok(_) => {
// SAFETY: A string is left in a valid state because appended bytes are nul-terminated.
// SAFETY: A string is left in a valid state because appended bytes are
// nul-terminated.
unsafe { self.extend_from_bytes_unchecked(bytes) }?;

Ok(())
Expand Down
60 changes: 35 additions & 25 deletions src/deque.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,18 @@
//! }
//! ```

use crate::vec::{OwnedVecStorage, VecStorage, VecStorageInner, ViewVecStorage};
use crate::CapacityError;
use core::cmp::Ordering;
use core::fmt;
use core::iter::FusedIterator;
use core::marker::PhantomData;
use core::mem::{ManuallyDrop, MaybeUninit};
use core::{ptr, slice};
use crate::{
vec::{OwnedVecStorage, VecStorage, VecStorageInner, ViewVecStorage},
CapacityError,
};
use core::{
cmp::Ordering,
fmt,
iter::FusedIterator,
marker::PhantomData,
mem::{ManuallyDrop, MaybeUninit},
ptr, slice,
};

#[cfg(feature = "zeroize")]
use zeroize::Zeroize;
Expand Down Expand Up @@ -173,14 +177,16 @@ impl<T, const N: usize> Deque<T, N> {

/// Returns the maximum number of elements the deque can hold.
///
/// This method is not available on a `DequeView`, use [`storage_capacity`](DequeInner::storage_capacity) instead.
/// This method is not available on a `DequeView`, use
/// [`storage_capacity`](DequeInner::storage_capacity) instead.
pub const fn capacity(&self) -> usize {
N
}

/// Returns the number of elements currently in the deque.
///
/// This method is not available on a `DequeView`, use [`storage_len`](DequeInner::storage_len) instead.
/// This method is not available on a `DequeView`, use [`storage_len`](DequeInner::storage_len)
/// instead.
pub const fn len(&self) -> usize {
if self.full {
N
Expand Down Expand Up @@ -452,8 +458,8 @@ impl<T, S: VecStorage<T> + ?Sized> DequeInner<T, S> {
self.storage_capacity() - free,
);

// because the deque wasn't contiguous, we know that `tail_len < self.len == slice.len()`,
// so this will never panic.
// because the deque wasn't contiguous, we know that `tail_len < self.len ==
// slice.len()`, so this will never panic.
slice.rotate_left(back_len);

// the used part of the buffer now is `free..self.capacity()`, so set
Expand All @@ -465,7 +471,8 @@ impl<T, S: VecStorage<T> + ?Sized> DequeInner<T, S> {
// head is shorter so:
// 1. copy head backwards
// 2. rotate used part of the buffer
// 3. update head to point to the new beginning (which is the beginning of the buffer)
// 3. update head to point to the new beginning (which is the beginning of the
// buffer)

unsafe {
// if there is no free space in the buffer, then the slices are already
Expand All @@ -483,8 +490,8 @@ impl<T, S: VecStorage<T> + ?Sized> DequeInner<T, S> {
// next to each other, all the elements in the range are initialized.
let slice: &mut [T] = slice::from_raw_parts_mut(buffer_ptr, len);

// because the deque wasn't contiguous, we know that `head_len < self.len == slice.len()`
// so this will never panic.
// because the deque wasn't contiguous, we know that `head_len < self.len ==
// slice.len()` so this will never panic.
slice.rotate_right(front_len);

// the used part of the buffer now is `0..self.len`, so set
Expand Down Expand Up @@ -844,11 +851,11 @@ impl<T, S: VecStorage<T> + ?Sized> DequeInner<T, S> {
}

// Safety:
// * Any slice passed to `drop_in_place` is valid; the second case has
// `len <= front.len()` and returning on `len > self.storage_len()` ensures
// `begin <= back.len()` in the first case
// * Deque front/back cursors are moved before calling `drop_in_place`,
// so no value is dropped twice if `drop_in_place` panics
// * Any slice passed to `drop_in_place` is valid; the second case has `len <= front.len()`
// and returning on `len > self.storage_len()` ensures `begin <= back.len()` in the first
// case
// * Deque front/back cursors are moved before calling `drop_in_place`, so no value is
// dropped twice if `drop_in_place` panics
unsafe {
// If new desired length is greater or equal, we don't need to act.
if len >= self.storage_len() {
Expand All @@ -865,8 +872,9 @@ impl<T, S: VecStorage<T> + ?Sized> DequeInner<T, S> {
let drop_back = back.get_unchecked_mut(begin..) as *mut _;

// Self::to_physical_index returns the index `len` units _after_ the front cursor,
// meaning we can use it to find the decremented index for `back` for non-contiguous deques,
// as well as determine where the new "cap" for front needs to be placed for contiguous deques.
// meaning we can use it to find the decremented index for `back` for non-contiguous
// deques, as well as determine where the new "cap" for front needs
// to be placed for contiguous deques.
self.back = self.to_physical_index(len);
self.full = false;

Expand All @@ -880,8 +888,9 @@ impl<T, S: VecStorage<T> + ?Sized> DequeInner<T, S> {
self.back = self.to_physical_index(len);
self.full = false;

// If `drop_front` causes a panic, the Dropper will still be called to drop it's slice during unwinding.
// In either case, front will always be dropped before back.
// If `drop_front` causes a panic, the Dropper will still be called to drop it's
// slice during unwinding. In either case, front will always be
// dropped before back.
let _back_dropper = Dropper(&mut *drop_back);
ptr::drop_in_place(drop_front);
}
Expand Down Expand Up @@ -970,7 +979,8 @@ impl<T, S: VecStorage<T> + ?Sized> DequeInner<T, S> {
cur += 1;
idx += 1;
}
// Stage 2: Swap retained values into current idx, building a contiguous chunk from 0 to idx.
// Stage 2: Swap retained values into current idx, building a contiguous chunk from 0 to
// idx.
while cur < len {
let val = self
.get_mut(cur)
Expand Down
40 changes: 22 additions & 18 deletions src/history_buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,7 @@
//! assert_eq!(avg, 4);
//! ```

use core::fmt;
use core::marker::PhantomData;
use core::mem::MaybeUninit;
use core::ops::Deref;
use core::ptr;
use core::slice;
use core::{fmt, marker::PhantomData, mem::MaybeUninit, ops::Deref, ptr, slice};

#[cfg(feature = "zeroize")]
use zeroize::Zeroize;
Expand All @@ -51,18 +46,23 @@ mod storage {
///
/// There's two implementations available:
///
/// - [`OwnedHistoryBufStorage`]: stores the data in an array `[T; N]` whose size is known at compile time.
/// - [`OwnedHistoryBufStorage`]: stores the data in an array `[T; N]` whose size is known at
/// compile time.
/// - [`ViewHistoryBufStorage`]: stores the data in an unsized `[T]`.
///
/// This allows [`HistoryBuf`] to be generic over either sized or unsized storage. The [`histbuf`]
/// module contains a [`HistoryBufInner`] struct that's generic on [`HistoryBufStorage`],
/// and two type aliases for convenience:
/// This allows [`HistoryBuf`] to be generic over either sized or unsized storage. The
/// [`histbuf`] module contains a [`HistoryBufInner`] struct that's generic on
/// [`HistoryBufStorage`], and two type aliases for convenience:
///
/// - [`HistoryBuf<T, N>`](super::HistoryBuf) = `HistoryBufInner<T, OwnedHistoryBufStorage<T, N>>`
/// - [`HistoryBufView<T>`](super::HistoryBufView) = `HistoryBufInner<T, ViewHistoryBufStorage<T>>`
/// - [`HistoryBuf<T, N>`](super::HistoryBuf) = `HistoryBufInner<T, OwnedHistoryBufStorage<T,
/// N>>`
/// - [`HistoryBufView<T>`](super::HistoryBufView) = `HistoryBufInner<T,
/// ViewHistoryBufStorage<T>>`
///
/// `HistoryBuf` can be unsized into `HistoryBufView`, either by unsizing coercions such as `&mut HistoryBuf -> &mut HistoryBufView` or
/// `Box<HistoryBuf> -> Box<HistoryBufView>`, or explicitly with [`.as_view()`](super::HistoryBuf::as_view) or [`.as_mut_view()`](super::HistoryBuf::as_mut_view).
/// `HistoryBuf` can be unsized into `HistoryBufView`, either by unsizing coercions such as
/// `&mut HistoryBuf -> &mut HistoryBufView` or `Box<HistoryBuf> -> Box<HistoryBufView>`, or
/// explicitly with [`.as_view()`](super::HistoryBuf::as_view) or
/// [`.as_mut_view()`](super::HistoryBuf::as_mut_view).
///
/// This trait is sealed, so you cannot implement it for your own types. You can only use
/// the implementations provided by this crate.
Expand All @@ -75,7 +75,8 @@ mod storage {
pub trait HistoryBufStorage<T>: HistoryBufSealedStorage<T> {}

pub trait HistoryBufSealedStorage<T> {
// part of the sealed trait so that no trait is publicly implemented by `OwnedHistoryBufStorage` besides `Storage`
// part of the sealed trait so that no trait is publicly implemented by
// `OwnedHistoryBufStorage` besides `Storage`
fn borrow(&self) -> &[MaybeUninit<T>];
fn borrow_mut(&mut self) -> &mut [MaybeUninit<T>];
fn as_hist_buf_view(this: &HistoryBufInner<T, Self>) -> &HistoryBufView<T>
Expand All @@ -92,7 +93,8 @@ mod storage {
pub(crate) buffer: T,
}

/// Implementation of [`HistoryBufStorage`] that stores the data in an array `[T; N]` whose size is known at compile time.
/// Implementation of [`HistoryBufStorage`] that stores the data in an array `[T; N]` whose size
/// is known at compile time.
pub type OwnedHistoryBufStorage<T, const N: usize> =
HistoryBufStorageInner<[MaybeUninit<T>; N]>;
/// Implementation of [`HistoryBufStorage`] that stores the data in an unsized `[T]`.
Expand Down Expand Up @@ -651,8 +653,10 @@ impl<T> DoubleEndedIterator for OldestOrdered<'_, T> {

#[cfg(test)]
mod tests {
use core::fmt::Debug;
use core::sync::atomic::{AtomicUsize, Ordering};
use core::{
fmt::Debug,
sync::atomic::{AtomicUsize, Ordering},
};

use static_assertions::assert_not_impl_any;

Expand Down
8 changes: 4 additions & 4 deletions src/index_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -665,8 +665,8 @@ where
match self.core.insert(self.hash_val, self.key, value) {
Insert::Success(inserted) => {
unsafe {
// SAFETY: Already checked existence at instantiation and the only mutable reference
// to the map is internally held.
// SAFETY: Already checked existence at instantiation and the only mutable
// reference to the map is internally held.
Ok(&mut (*self.core.entries.as_mut_ptr().add(inserted.index)).value)
}
}
Expand Down Expand Up @@ -1592,8 +1592,8 @@ impl<'a, K, V> Iterator for Values<'a, K, V> {

/// A mutable iterator over the values of a [`IndexMap`].
///
/// This `struct` is created by the [`values_mut`](IndexMap::values_mut) method on [`IndexMap`]. See its
/// documentation for more.
/// This `struct` is created by the [`values_mut`](IndexMap::values_mut) method on [`IndexMap`]. See
/// its documentation for more.
pub struct ValuesMut<'a, K, V> {
iter: slice::IterMut<'a, Bucket<K, V>>,
}
Expand Down
18 changes: 11 additions & 7 deletions src/linear_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,17 @@ mod storage {
/// - [`OwnedStorage`]: stores the data in an array whose size is known at compile time.
/// - [`ViewStorage`]: stores the data in an unsized slice
///
/// This allows [`LinearMap`] to be generic over either sized or unsized storage. The [`linear_map`](super)
/// module contains a [`LinearMapInner`] struct that's generic on [`LinearMapStorage`],
/// and two type aliases for convenience:
/// This allows [`LinearMap`] to be generic over either sized or unsized storage. The
/// [`linear_map`](super) module contains a [`LinearMapInner`] struct that's generic on
/// [`LinearMapStorage`], and two type aliases for convenience:
///
/// - [`LinearMap<N>`](crate::linear_map::LinearMap) = `LinearMapInner<OwnedStorage<u8, N>>`
/// - [`LinearMapView<T>`](crate::linear_map::LinearMapView) = `LinearMapInner<ViewStorage<u8>>`
///
/// `LinearMap` can be unsized into `StrinsgView`, either by unsizing coercions such as `&mut LinearMap -> &mut LinearMapView` or
/// `Box<LinearMap> -> Box<LinearMapView>`, or explicitly with [`.as_view()`](crate::linear_map::LinearMap::as_view) or [`.as_mut_view()`](crate::linear_map::LinearMap::as_mut_view).
/// `LinearMap` can be unsized into `StrinsgView`, either by unsizing coercions such as `&mut
/// LinearMap -> &mut LinearMapView` or `Box<LinearMap> -> Box<LinearMapView>`, or
/// explicitly with [`.as_view()`](crate::linear_map::LinearMap::as_view) or
/// [`.as_mut_view()`](crate::linear_map::LinearMap::as_mut_view).
///
/// This trait is sealed, so you cannot implement it for your own types. You can only use
/// the implementations provided by this crate.
Expand Down Expand Up @@ -85,7 +87,8 @@ mod storage {
}

pub use storage::LinearMapStorage;
/// Implementation of [`LinearMapStorage`] that stores the data in an array whose size is known at compile time.
/// Implementation of [`LinearMapStorage`] that stores the data in an array whose size is known at
/// compile time.
pub type OwnedStorage<K, V, const N: usize> = OwnedVecStorage<(K, V), N>;
/// Implementation of [`LinearMapStorage`] that stores the data in an unsized slice.
pub type ViewStorage<K, V> = ViewVecStorage<(K, V)>;
Expand Down Expand Up @@ -590,7 +593,8 @@ where

/// An iterator that moves out of a [`LinearMap`].
///
/// This struct is created by calling the [`into_iter`](LinearMap::into_iter) method on [`LinearMap`].
/// This struct is created by calling the [`into_iter`](LinearMap::into_iter) method on
/// [`LinearMap`].
pub struct IntoIter<K, V, const N: usize>
where
K: Eq,
Expand Down
27 changes: 15 additions & 12 deletions src/mpmc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@
//!
//! # Benchmark
//!
//! Measured on an ARM Cortex-M3 core running at 8 MHz and with zero flash wait cycles, compiled with `-C opt-level=z`:
//! Measured on an ARM Cortex-M3 core running at 8 MHz and with zero flash wait cycles, compiled
//! with `-C opt-level=z`:
//!
//! | Method | Time | N |
//! |:----------------------------|-----:|---:|
Expand All @@ -80,15 +81,14 @@
//! | `Queue::<u8, 8>::dequeue()` | 53 | 1 |
//! | `Queue::<u8, 8>::dequeue()` | 71 | 2 |
//!
//! - 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`
//! operation. Note that it does *not* matter if the higher priority handler uses the queue or
//! not.
//! - 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` 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).
//! - Execution time is *dependent* on `mem::size_of::<T>()`, as both operations include
//! `ptr::read::<T>()` or `ptr::write::<T>()` in their successful path.
//! - The numbers reported correspond to the successful path, i.e. `dequeue` returning `Some`
//! and `enqueue` returning `Ok`.
//! - The numbers reported correspond to the successful path, i.e. `dequeue` returning `Some` and
//! `enqueue` returning `Ok`.
//!
//! # References
//!
Expand Down Expand Up @@ -146,7 +146,8 @@ pub type Queue<T, const N: usize> = QueueInner<T, OwnedStorage<N>>;

/// A [`Queue`] with dynamic capacity.
///
/// [`Queue`] coerces to `QueueView`. `QueueView` is `!Sized`, meaning it can only ever be used by reference.
/// [`Queue`] coerces to `QueueView`. `QueueView` is `!Sized`, meaning it can only ever be used by
/// reference.
pub type QueueView<T> = QueueInner<T, ViewStorage>;

impl<T, const N: usize> Queue<T, N> {
Expand All @@ -158,8 +159,8 @@ impl<T, const N: usize> Queue<T, N> {
/// # Deprecation
///
/// <div class="warning">
/// The current implementation of `mpmc` is marked as deprecated due to not being truly lock-free
/// </div>
/// The current implementation of `mpmc` is marked as deprecated due to not being truly
/// lock-free </div>
///
/// If a thread is parked, or pre-empted for a long time by an higher-priority task
/// during an `enqueue` or `dequeue` operation, it is possible that the queue ends-up
Expand Down Expand Up @@ -230,7 +231,8 @@ impl<T, S: Storage> QueueInner<T, S> {
/// let view: &QueueView<u8> = queue.as_view();
/// ```
///
/// It is often preferable to do the same through type coerction, since `Queue<T, N>` implements `Unsize<QueueView<T>>`:
/// It is often preferable to do the same through type coerction, since `Queue<T, N>` implements
/// `Unsize<QueueView<T>>`:
///
/// ```rust
/// # use heapless::mpmc::{Queue, QueueView};
Expand All @@ -251,7 +253,8 @@ impl<T, S: Storage> QueueInner<T, S> {
/// let view: &mut QueueView<u8> = queue.as_mut_view();
/// ```
///
/// It is often preferable to do the same through type coerction, since `Queue<T, N>` implements `Unsize<QueueView<T>>`:
/// It is often preferable to do the same through type coerction, since `Queue<T, N>` implements
/// `Unsize<QueueView<T>>`:
///
/// ```rust
/// # use heapless::mpmc::{Queue, QueueView};
Expand Down
Loading
Loading