92: use core::mem::MaybeUninit; drop min-const-fn and smaller-atomics features r=japaric a=japaric

closes #69 

this contains breaking changes (see CHANGELOG) and bumps the crate version to 0.5.0. We'll make a pre-release (i.e. v0.5.0-alpha.1) after rust-lang/rust#60445 lands and a proper release when that PR makes into the stable channel.

Co-authored-by: Jorge Aparicio <jorge@japaric.io>
This commit is contained in:
bors[bot] 2019-05-03 13:58:22 +00:00
commit 91dfd3ccb8
20 changed files with 203 additions and 428 deletions

View File

@ -2,22 +2,10 @@ language: rust
matrix: matrix:
include: include:
# MSRV # TODO MSRV
- env: TARGET=x86_64-unknown-linux-gnu # - env: TARGET=x86_64-unknown-linux-gnu
rust: 1.30.0 # rust: 1.36.0
if: branch != master # if: branch != master
- env: TARGET=x86_64-unknown-linux-gnu
rust: stable
if: branch != master
- env: TARGET=thumbv6m-none-eabi
rust: beta
if: branch != master
- env: TARGET=thumbv7m-none-eabi
rust: stable
if: branch != master
- env: TARGET=x86_64-unknown-linux-gnu - env: TARGET=x86_64-unknown-linux-gnu
rust: nightly rust: nightly

View File

@ -7,6 +7,21 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased] ## [Unreleased]
## [v0.5.0] - 2019-06-xx
### Removed
- [breaking-change] The "smaller-atomics" feature has been removed. It is now
always enabled.
- [breaking-change] The "min-const-fn" feature has been removed. It is now
always enabled.
- [breaking-change] The MSRV has been bumped to Rust 1.36.0.
- [breaking-change] The version of the `generic-array` dependency has been
bumped to v0.13.0.
## [v0.4.4] - 2019-05-02 ## [v0.4.4] - 2019-05-02
### Added ### Added

View File

@ -9,6 +9,7 @@ categories = [
] ]
description = "`static` friendly data structures that don't require dynamic memory allocation" description = "`static` friendly data structures that don't require dynamic memory allocation"
documentation = "https://japaric.github.io/heapless/heapless/index.html" documentation = "https://japaric.github.io/heapless/heapless/index.html"
edition = "2018"
keywords = [ keywords = [
"static", "static",
"no-heap", "no-heap",
@ -16,19 +17,17 @@ 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.4.4" version = "0.5.0-alpha.1"
[features] [features]
const-fn = ["min-const-fn"] const-fn = []
min-const-fn = []
smaller-atomics = []
[dev-dependencies] [dev-dependencies]
scoped_threadpool = "0.1.8" scoped_threadpool = "0.1.8"
[dependencies] [dependencies]
as-slice = "0.1.0" as-slice = "0.1.0"
generic-array = "0.11.0" generic-array = "0.13.0"
hash32 = "0.1.0" hash32 = "0.1.0"
[dependencies.serde] [dependencies.serde]
@ -37,4 +36,4 @@ optional = true
default-features = false default-features = false
[package.metadata.docs.rs] [package.metadata.docs.rs]
features = ["const-fn", "smaller-atomics"] features = ["const-fn"]

View File

@ -3,7 +3,7 @@ set -euxo pipefail
main() { main() {
cargo check --target $TARGET --features 'serde' cargo check --target $TARGET --features 'serde'
if [ $TRAVIS_RUST_VERSION = nightly ]; then if [ $TRAVIS_RUST_VERSION = nightly ]; then
cargo check --target $TARGET --features 'const-fn smaller-atomics' cargo check --target $TARGET --features 'const-fn'
fi fi
if [ $TARGET = x86_64-unknown-linux-gnu ]; then if [ $TARGET = x86_64-unknown-linux-gnu ]; then
@ -11,17 +11,17 @@ main() {
cargo test --target $TARGET --release --features 'serde' cargo test --target $TARGET --release --features 'serde'
if [ $TRAVIS_RUST_VERSION = nightly ]; then if [ $TRAVIS_RUST_VERSION = nightly ]; then
cargo test --target $TARGET --features 'const-fn smaller-atomics' cargo test --target $TARGET --features 'const-fn'
cargo test --target $TARGET --release --features 'const-fn smaller-atomics' cargo test --target $TARGET --release --features 'const-fn'
export RUSTFLAGS="-Z sanitizer=thread" export RUSTFLAGS="-Z sanitizer=thread"
export RUST_TEST_THREADS=1 export RUST_TEST_THREADS=1
export TSAN_OPTIONS="suppressions=$(pwd)/blacklist.txt" export TSAN_OPTIONS="suppressions=$(pwd)/blacklist.txt"
cargo test --test tsan --target $TARGET cargo test --test tsan --target $TARGET
cargo test --test tsan --target $TARGET --features 'const-fn smaller-atomics' cargo test --test tsan --target $TARGET --features 'const-fn'
cargo test --test tsan --target $TARGET --release cargo test --test tsan --target $TARGET --release
cargo test --test tsan --target $TARGET --release --features 'const-fn smaller-atomics' cargo test --test tsan --target $TARGET --release --features 'const-fn'
fi fi
fi fi
} }

View File

@ -1,54 +0,0 @@
/// Temporary fork of some stuff in `core` that's doesn't have a `const fn` API
pub mod mem {
#[cfg(not(feature = "const-fn"))]
pub use core::mem;
pub use core::mem::{replace, zeroed, ManuallyDrop};
// See RFC 1892
#[cfg(feature = "const-fn")]
pub union MaybeUninit<T> {
uninit: (),
value: ManuallyDrop<T>,
}
// workaround to get this to compile on stable ("unions with non-`Copy` fields are unstable")
#[cfg(not(feature = "const-fn"))]
pub struct MaybeUninit<T> {
value: ManuallyDrop<T>,
}
impl<T> MaybeUninit<T> {
#[cfg(feature = "const-fn")]
pub const unsafe fn uninitialized() -> Self {
MaybeUninit { uninit: () }
}
#[cfg(not(feature = "const-fn"))]
pub unsafe fn uninitialized() -> Self {
MaybeUninit {
value: ManuallyDrop::new(mem::uninitialized()),
}
}
/// Get a reference to the contained value.
///
/// # Unsafety
///
/// It is up to the caller to guarantee that the the `MaybeUninit` really is in an
/// initialized state, otherwise this will immediately cause undefined behavior.
pub unsafe fn get_ref(&self) -> &T {
&*self.value
}
/// Get a mutable reference to the contained value.
///
/// # Unsafety
///
/// It is up to the caller to guarantee that the the `MaybeUninit` really is in an
/// initialized state, otherwise this will immediately cause undefined behavior.
pub unsafe fn get_mut(&mut self) -> &mut T {
&mut *self.value
}
}
}

View File

@ -8,14 +8,17 @@
// heap can also be converted to a sorted vector in-place, allowing it to be used for an `O(n log // 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. // n)` in-place heapsort.
use core::cmp::Ordering; use core::{
use core::marker::PhantomData; cmp::Ordering,
use core::mem::ManuallyDrop; fmt,
use core::{mem, ptr, slice, fmt}; marker::PhantomData,
mem::{self, ManuallyDrop},
ptr, slice,
};
use generic_array::ArrayLength; use generic_array::ArrayLength;
use Vec; use crate::Vec;
/// Min-heap /// Min-heap
pub enum Min {} pub enum Min {}
@ -206,7 +209,7 @@ where
/// ///
/// } /// }
/// ``` /// ```
pub fn iter(&self) -> slice::Iter<T> { pub fn iter(&self) -> slice::Iter<'_, T> {
self.data.iter() self.data.iter()
} }
@ -214,7 +217,7 @@ where
/// ///
/// **WARNING** Mutating the items in the binary heap can leave the heap in an inconsistent /// **WARNING** Mutating the items in the binary heap can leave the heap in an inconsistent
/// state. /// state.
pub fn iter_mut(&mut self) -> slice::IterMut<T> { pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> {
self.data.iter_mut() self.data.iter_mut()
} }
@ -344,7 +347,7 @@ where
/// (because it was moved from or duplicated). /// (because it was moved from or duplicated).
/// In drop, `Hole` will restore the slice by filling the hole /// In drop, `Hole` will restore the slice by filling the hole
/// position with the value that was originally removed. /// position with the value that was originally removed.
struct Hole<'a, T: 'a> { struct Hole<'a, T> {
data: &'a mut [T], data: &'a mut [T],
/// `elt` is always `Some` from new until drop. /// `elt` is always `Some` from new until drop.
elt: ManuallyDrop<T>, elt: ManuallyDrop<T>,
@ -441,9 +444,9 @@ impl<T, N, K> fmt::Debug for BinaryHeap<T, N, K>
where where
N: ArrayLength<T>, N: ArrayLength<T>,
K: Kind, K: Kind,
T: Ord + fmt::Debug T: Ord + fmt::Debug,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish() f.debug_list().entries(self.iter()).finish()
} }
} }
@ -466,8 +469,10 @@ where
mod tests { mod tests {
use std::vec::Vec; use std::vec::Vec;
use binary_heap::{self, BinaryHeap, Min}; use crate::{
use consts::*; binary_heap::{self, BinaryHeap, Min},
consts::*,
};
#[cfg(feature = "const-fn")] #[cfg(feature = "const-fn")]
#[test] #[test]

View File

@ -33,36 +33,3 @@ macro_rules! const_fn {
fn $($f)* fn $($f)*
); );
} }
#[cfg(not(armv6m))]
macro_rules! min_const_fn {
($(#[$attr:meta])* pub const unsafe fn $($f:tt)*) => (
$(#[$attr])*
#[cfg(feature = "min-const-fn")]
pub const unsafe fn $($f)*
$(#[$attr])*
#[cfg(not(feature = "min-const-fn"))]
pub unsafe fn $($f)*
);
($(#[$attr:meta])* pub const fn $($f:tt)*) => (
$(#[$attr])*
#[cfg(feature = "min-const-fn")]
pub const fn $($f)*
$(#[$attr])*
#[cfg(not(feature = "min-const-fn"))]
pub fn $($f)*
);
($(#[$attr:meta])* const fn $($f:tt)*) => (
$(#[$attr])*
#[cfg(feature = "min-const-fn")]
const fn $($f)*
$(#[$attr])*
#[cfg(not(feature = "min-const-fn"))]
fn $($f)*
);
}

View File

@ -1,18 +1,14 @@
use core::fmt; use core::{fmt, marker::PhantomData};
use core::marker::PhantomData;
use generic_array::{typenum::PowerOfTwo, ArrayLength}; use generic_array::{typenum::PowerOfTwo, ArrayLength};
use hash32::{BuildHasherDefault, Hash, Hasher}; use hash32::{BuildHasherDefault, Hash, Hasher};
use serde::de::{self, Deserialize, Deserializer, Error, MapAccess, SeqAccess}; use serde::de::{self, Deserialize, Deserializer, Error, MapAccess, SeqAccess};
use super::binary_heap::Kind as BinaryHeapKind; use crate::{
use super::indexmap::{Bucket, Pos}; binary_heap,
use BinaryHeap; indexmap::{Bucket, Pos},
use IndexMap; BinaryHeap, IndexMap, IndexSet, LinearMap, String, Vec,
use IndexSet; };
use LinearMap;
use String;
use Vec;
// Sequential containers // Sequential containers
@ -20,7 +16,7 @@ impl<'de, T, N, KIND> Deserialize<'de> for BinaryHeap<T, N, KIND>
where where
T: Ord + Deserialize<'de>, T: Ord + Deserialize<'de>,
N: ArrayLength<T>, N: ArrayLength<T>,
KIND: BinaryHeapKind, KIND: binary_heap::Kind,
{ {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where where
@ -32,11 +28,11 @@ where
where where
T: Ord + Deserialize<'de>, T: Ord + Deserialize<'de>,
N: ArrayLength<T>, N: ArrayLength<T>,
KIND: BinaryHeapKind, KIND: binary_heap::Kind,
{ {
type Value = BinaryHeap<T, N, KIND>; type Value = BinaryHeap<T, N, KIND>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a sequence") formatter.write_str("a sequence")
} }
@ -79,7 +75,7 @@ where
{ {
type Value = IndexSet<T, N, BuildHasherDefault<S>>; type Value = IndexSet<T, N, BuildHasherDefault<S>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a sequence") formatter.write_str("a sequence")
} }
@ -120,7 +116,7 @@ where
{ {
type Value = Vec<T, N>; type Value = Vec<T, N>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a sequence") formatter.write_str("a sequence")
} }
@ -167,7 +163,7 @@ where
{ {
type Value = IndexMap<K, V, N, BuildHasherDefault<S>>; type Value = IndexMap<K, V, N, BuildHasherDefault<S>>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a map") formatter.write_str("a map")
} }
@ -210,7 +206,7 @@ where
{ {
type Value = LinearMap<K, V, N>; type Value = LinearMap<K, V, N>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a map") formatter.write_str("a map")
} }
@ -251,7 +247,7 @@ where
{ {
type Value = String<N>; type Value = String<N>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
formatter, formatter,
"a string no more than {} bytes long", "a string no more than {} bytes long",

View File

@ -1,15 +1,16 @@
use core::borrow::Borrow; use core::{
use core::iter::FromIterator; borrow::Borrow,
use core::num::NonZeroU32; fmt,
use core::{fmt, ops, slice}; iter::FromIterator,
mem::{self, MaybeUninit},
use generic_array::typenum::PowerOfTwo; num::NonZeroU32,
use generic_array::{ArrayLength, GenericArray}; ops, slice,
};
use generic_array::{typenum::PowerOfTwo, ArrayLength, GenericArray};
use hash32::{BuildHasher, BuildHasherDefault, FnvHasher, Hash, Hasher}; use hash32::{BuildHasher, BuildHasherDefault, FnvHasher, Hash, Hasher};
use Vec; use crate::Vec;
use __core::mem;
/// An `IndexMap` using the default FNV hasher /// An `IndexMap` using the default FNV hasher
pub type FnvIndexMap<K, V, N> = IndexMap<K, V, N, BuildHasherDefault<FnvHasher>>; pub type FnvIndexMap<K, V, N> = IndexMap<K, V, N, BuildHasherDefault<FnvHasher>>;
@ -102,7 +103,7 @@ where
fn new() -> Self { fn new() -> Self {
CoreMap { CoreMap {
entries: Vec::new(), entries: Vec::new(),
indices: unsafe { mem::zeroed() }, indices: unsafe { MaybeUninit::zeroed().assume_init() },
} }
} }
@ -440,7 +441,7 @@ where
/// println!("key: {} val: {}", key, val); /// println!("key: {} val: {}", key, val);
/// } /// }
/// ``` /// ```
pub fn iter(&self) -> Iter<K, V> { pub fn iter(&self) -> Iter<'_, K, V> {
Iter { Iter {
iter: self.core.entries.iter(), iter: self.core.entries.iter(),
} }
@ -465,7 +466,7 @@ where
/// println!("key: {} val: {}", key, val); /// println!("key: {} val: {}", key, val);
/// } /// }
/// ``` /// ```
pub fn iter_mut(&mut self) -> IterMut<K, V> { pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
IterMut { IterMut {
iter: self.core.entries.iter_mut(), iter: self.core.entries.iter_mut(),
} }
@ -762,7 +763,7 @@ where
S: BuildHasher, S: BuildHasher,
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>, N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.iter()).finish() f.debug_map().entries(self.iter()).finish()
} }
} }
@ -805,10 +806,8 @@ where
S: BuildHasher, S: BuildHasher,
N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>, N: ArrayLength<Bucket<K, V>> + ArrayLength<Option<Pos>>,
{ {
} }
impl<K, V, N, S> Extend<(K, V)> for IndexMap<K, V, N, S> impl<K, V, N, S> Extend<(K, V)> for IndexMap<K, V, N, S>
where where
K: Eq + Hash, K: Eq + Hash,
@ -884,19 +883,11 @@ where
} }
} }
pub struct Iter<'a, K, V> pub struct Iter<'a, K, V> {
where
K: 'a,
V: 'a,
{
iter: slice::Iter<'a, Bucket<K, V>>, iter: slice::Iter<'a, Bucket<K, V>>,
} }
impl<'a, K, V> Iterator for Iter<'a, K, V> impl<'a, K, V> Iterator for Iter<'a, K, V> {
where
K: 'a,
V: 'a,
{
type Item = (&'a K, &'a V); type Item = (&'a K, &'a V);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -904,11 +895,7 @@ where
} }
} }
impl<'a, K, V> Clone for Iter<'a, K, V> impl<'a, K, V> Clone for Iter<'a, K, V> {
where
K: 'a,
V: 'a,
{
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
iter: self.iter.clone(), iter: self.iter.clone(),
@ -916,19 +903,11 @@ where
} }
} }
pub struct IterMut<'a, K, V> pub struct IterMut<'a, K, V> {
where
K: 'a,
V: 'a,
{
iter: slice::IterMut<'a, Bucket<K, V>>, iter: slice::IterMut<'a, Bucket<K, V>>,
} }
impl<'a, K, V> Iterator for IterMut<'a, K, V> impl<'a, K, V> Iterator for IterMut<'a, K, V> {
where
K: 'a,
V: 'a,
{
type Item = (&'a K, &'a mut V); type Item = (&'a K, &'a mut V);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -954,8 +933,7 @@ mod tests {
use generic_array::typenum::Unsigned; use generic_array::typenum::Unsigned;
use consts::*; use crate::{consts::*, FnvIndexMap};
use FnvIndexMap;
#[test] #[test]
fn size() { fn size() {
@ -973,14 +951,13 @@ mod tests {
) )
} }
#[test] #[test]
fn partial_eq() { fn partial_eq() {
{ {
let mut a: FnvIndexMap<_, _, U4> = FnvIndexMap::new(); let mut a: FnvIndexMap<_, _, U4> = FnvIndexMap::new();
a.insert("k1", "v1").unwrap(); a.insert("k1", "v1").unwrap();
let mut b: FnvIndexMap<_, _, U4> = FnvIndexMap::new(); let mut b: FnvIndexMap<_, _, U4> = FnvIndexMap::new();
b.insert("k1", "v1").unwrap(); b.insert("k1", "v1").unwrap();
assert!(a == b); assert!(a == b);
@ -991,11 +968,11 @@ mod tests {
} }
{ {
let mut a: FnvIndexMap<_, _, U4> = FnvIndexMap::new(); let mut a: FnvIndexMap<_, _, U4> = FnvIndexMap::new();
a.insert("k1", "v1").unwrap(); a.insert("k1", "v1").unwrap();
a.insert("k2", "v2").unwrap(); a.insert("k2", "v2").unwrap();
let mut b: FnvIndexMap<_, _, U4> = FnvIndexMap::new(); let mut b: FnvIndexMap<_, _, U4> = FnvIndexMap::new();
b.insert("k2", "v2").unwrap(); b.insert("k2", "v2").unwrap();
b.insert("k1", "v1").unwrap(); b.insert("k1", "v1").unwrap();

View File

@ -1,12 +1,9 @@
use core::borrow::Borrow; use core::{borrow::Borrow, fmt, iter::FromIterator};
use core::fmt;
use core::iter::FromIterator;
use generic_array::typenum::PowerOfTwo; use generic_array::{typenum::PowerOfTwo, ArrayLength};
use generic_array::ArrayLength;
use hash32::{BuildHasher, BuildHasherDefault, FnvHasher, Hash, Hasher}; use hash32::{BuildHasher, BuildHasherDefault, FnvHasher, Hash, Hasher};
use indexmap::{self, Bucket, IndexMap, Pos}; use crate::indexmap::{self, Bucket, IndexMap, Pos};
/// An `IndexSet` using the default FNV hasher /// An `IndexSet` using the default FNV hasher
pub type FnvIndexSet<T, N> = IndexSet<T, N, BuildHasherDefault<FnvHasher>>; pub type FnvIndexSet<T, N> = IndexSet<T, N, BuildHasherDefault<FnvHasher>>;
@ -104,7 +101,7 @@ where
/// println!("{}", x); /// println!("{}", x);
/// } /// }
/// ``` /// ```
pub fn iter(&self) -> Iter<T> { pub fn iter(&self) -> Iter<'_, T> {
Iter { Iter {
iter: self.map.iter(), iter: self.map.iter(),
} }
@ -473,7 +470,7 @@ where
S: BuildHasher, S: BuildHasher,
N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>, N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_set().entries(self.iter()).finish() f.debug_set().entries(self.iter()).finish()
} }
} }
@ -562,17 +559,11 @@ where
} }
} }
pub struct Iter<'a, T> pub struct Iter<'a, T> {
where
T: 'a,
{
iter: indexmap::Iter<'a, T, ()>, iter: indexmap::Iter<'a, T, ()>,
} }
impl<'a, T> Iterator for Iter<'a, T> impl<'a, T> Iterator for Iter<'a, T> {
where
T: 'a,
{
type Item = &'a T; type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -580,10 +571,7 @@ where
} }
} }
impl<'a, T> Clone for Iter<'a, T> impl<'a, T> Clone for Iter<'a, T> {
where
T: 'a,
{
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
iter: self.iter.clone(), iter: self.iter.clone(),
@ -593,9 +581,9 @@ where
pub struct Difference<'a, T, N, S> pub struct Difference<'a, T, N, S>
where where
S: 'a + BuildHasher, S: BuildHasher,
T: 'a + Eq + Hash, T: Eq + Hash,
N: 'a + ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>, N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
{ {
iter: Iter<'a, T>, iter: Iter<'a, T>,
other: &'a IndexSet<T, N, S>, other: &'a IndexSet<T, N, S>,
@ -603,9 +591,9 @@ where
impl<'a, T, N, S> Iterator for Difference<'a, T, N, S> impl<'a, T, N, S> Iterator for Difference<'a, T, N, S>
where where
S: 'a + BuildHasher, S: BuildHasher,
T: 'a + Eq + Hash, T: Eq + Hash,
N: 'a + ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>, N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
{ {
type Item = &'a T; type Item = &'a T;
@ -621,9 +609,9 @@ where
pub struct Intersection<'a, T, N, S> pub struct Intersection<'a, T, N, S>
where where
S: 'a + BuildHasher, S: BuildHasher,
T: 'a + Eq + Hash, T: Eq + Hash,
N: 'a + ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>, N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
{ {
iter: Iter<'a, T>, iter: Iter<'a, T>,
other: &'a IndexSet<T, N, S>, other: &'a IndexSet<T, N, S>,
@ -631,9 +619,9 @@ where
impl<'a, T, N, S> Iterator for Intersection<'a, T, N, S> impl<'a, T, N, S> Iterator for Intersection<'a, T, N, S>
where where
S: 'a + BuildHasher, S: BuildHasher,
T: 'a + Eq + Hash, T: Eq + Hash,
N: 'a + ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>, N: ArrayLength<Bucket<T, ()>> + ArrayLength<Option<Pos>>,
{ {
type Item = &'a T; type Item = &'a T;

View File

@ -57,7 +57,7 @@
//! //!
//! # Minimum Supported Rust Version (MSRV) //! # Minimum Supported Rust Version (MSRV)
//! //!
//! This crate is guaranteed to compile on stable Rust 1.30 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.
//! It *might* compile on older versions but that may change in any new patch release. //! It *might* compile on older versions but that may change in any new patch release.
//! //!
//! # Cargo features //! # Cargo features
@ -79,28 +79,14 @@
//! //!
//! - `"const-fn"` -- Enables the nightly `const_fn` and `untagged_unions` features and makes most //! - `"const-fn"` -- Enables the nightly `const_fn` and `untagged_unions` features and makes most
//! `new` methods `const`. This way they can be used to initialize static memory at compile time. //! `new` methods `const`. This way they can be used to initialize static memory at compile time.
//!
//! - `"min-const-fn"` -- Turns `Pool::new` into a const fn and makes the `pool!` macro available.
//! This bumps the required Rust version to 1.31.0.
//!
//! - `"smaller-atomics"` -- Lets you initialize `spsc::Queue`s with smaller head / tail indices
//! (they default to `usize`), shrinking the overall size of the queue.
#![allow(warnings)]
#![deny(missing_docs)]
#![deny(warnings)]
#![cfg_attr(feature = "const-fn", feature(const_fn))] #![cfg_attr(feature = "const-fn", feature(const_fn))]
#![cfg_attr(feature = "const-fn", feature(untagged_unions))] #![cfg_attr(not(test), no_std)]
#![no_std] #![deny(missing_docs)]
#![deny(rust_2018_compatibility)]
extern crate as_slice; #![deny(rust_2018_idioms)]
extern crate generic_array; #![deny(warnings)]
extern crate hash32; #![feature(maybe_uninit)]
#[cfg(test)]
extern crate std;
#[cfg(feature = "serde")]
extern crate serde;
#[macro_use] #[macro_use]
mod const_fn; mod const_fn;
@ -131,5 +117,4 @@ pub mod binary_heap;
pub mod pool; pub mod pool;
pub mod spsc; pub mod spsc;
mod __core;
mod sealed; mod sealed;

View File

@ -1,10 +1,8 @@
use core::borrow::Borrow; use core::{borrow::Borrow, fmt, iter::FromIterator, mem, ops, slice};
use core::{mem, ops, slice, fmt};
use core::iter::FromIterator;
use generic_array::ArrayLength; use generic_array::ArrayLength;
use Vec; use crate::Vec;
/// A fixed capacity map / dictionary that performs lookups via linear search /// A fixed capacity map / dictionary that performs lookups via linear search
/// ///
@ -232,7 +230,7 @@ where
/// println!("key: {} val: {}", key, val); /// println!("key: {} val: {}", key, val);
/// } /// }
/// ``` /// ```
pub fn iter(&self) -> Iter<K, V> { pub fn iter(&self) -> Iter<'_, K, V> {
Iter { Iter {
iter: self.buffer.iter(), iter: self.buffer.iter(),
} }
@ -261,7 +259,7 @@ where
/// println!("key: {} val: {}", key, val); /// println!("key: {} val: {}", key, val);
/// } /// }
/// ``` /// ```
pub fn iter_mut(&mut self) -> IterMut<K, V> { pub fn iter_mut(&mut self) -> IterMut<'_, K, V> {
IterMut { IterMut {
iter: self.buffer.iter_mut(), iter: self.buffer.iter_mut(),
} }
@ -370,7 +368,6 @@ where
N: ArrayLength<(K, V)>, N: ArrayLength<(K, V)>,
K: Borrow<Q> + Eq, K: Borrow<Q> + Eq,
Q: Eq + ?Sized, Q: Eq + ?Sized,
V: 'a,
{ {
type Output = V; type Output = V;
@ -384,7 +381,6 @@ where
N: ArrayLength<(K, V)>, N: ArrayLength<(K, V)>,
K: Borrow<Q> + Eq, K: Borrow<Q> + Eq,
Q: Eq + ?Sized, Q: Eq + ?Sized,
V: 'a,
{ {
fn index_mut(&mut self, key: &Q) -> &mut V { fn index_mut(&mut self, key: &Q) -> &mut V {
self.get_mut(key).expect("no entry found for key") self.get_mut(key).expect("no entry found for key")
@ -420,7 +416,7 @@ where
K: Eq + fmt::Debug, K: Eq + fmt::Debug,
V: fmt::Debug, V: fmt::Debug,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map().entries(self.iter()).finish() f.debug_map().entries(self.iter()).finish()
} }
} }
@ -487,19 +483,11 @@ where
} }
} }
pub struct Iter<'a, K, V> pub struct Iter<'a, K, V> {
where
K: 'a,
V: 'a,
{
iter: slice::Iter<'a, (K, V)>, iter: slice::Iter<'a, (K, V)>,
} }
impl<'a, K, V> Iterator for Iter<'a, K, V> impl<'a, K, V> Iterator for Iter<'a, K, V> {
where
K: 'a,
V: 'a,
{
type Item = (&'a K, &'a V); type Item = (&'a K, &'a V);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -507,11 +495,7 @@ where
} }
} }
impl<'a, K, V> Clone for Iter<'a, K, V> impl<'a, K, V> Clone for Iter<'a, K, V> {
where
K: 'a,
V: 'a,
{
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
iter: self.iter.clone(), iter: self.iter.clone(),
@ -519,19 +503,11 @@ where
} }
} }
pub struct IterMut<'a, K, V> pub struct IterMut<'a, K, V> {
where
K: 'a,
V: 'a,
{
iter: slice::IterMut<'a, (K, V)>, iter: slice::IterMut<'a, (K, V)>,
} }
impl<'a, K, V> Iterator for IterMut<'a, K, V> impl<'a, K, V> Iterator for IterMut<'a, K, V> {
where
K: 'a,
V: 'a,
{
type Item = (&'a K, &'a mut V); type Item = (&'a K, &'a mut V);
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
@ -562,11 +538,9 @@ where
{ {
} }
#[cfg(feature = "const-fn")] // Remove this if there are more tests
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use consts::*; use crate::{consts::*, LinearMap};
use LinearMap;
#[cfg(feature = "const-fn")] #[cfg(feature = "const-fn")]
#[test] #[test]

View File

@ -159,7 +159,6 @@ use core::{
ptr::{self, NonNull}, ptr::{self, NonNull},
sync::atomic::AtomicPtr, sync::atomic::AtomicPtr,
}; };
#[cfg(not(armv6m))] #[cfg(not(armv6m))]
use core::{any::TypeId, mem, sync::atomic::Ordering}; use core::{any::TypeId, mem, sync::atomic::Ordering};
@ -185,14 +184,12 @@ unsafe impl<T> Sync for Pool<T> {}
unsafe impl<T> Send for Pool<T> {} unsafe impl<T> Send for Pool<T> {}
impl<T> Pool<T> { impl<T> Pool<T> {
min_const_fn! { /// Creates a new empty pool
/// Creates a new empty pool pub const fn new() -> Self {
pub const fn new() -> Self { Pool {
Pool { head: AtomicPtr::new(ptr::null_mut()),
head: AtomicPtr::new(ptr::null_mut()),
_not_send_or_sync: PhantomData, _not_send_or_sync: PhantomData,
}
} }
} }
@ -386,7 +383,7 @@ impl<T> fmt::Debug for Box<T>
where where
T: fmt::Debug, T: fmt::Debug,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<T as fmt::Debug>::fmt(self, f) <T as fmt::Debug>::fmt(self, f)
} }
} }
@ -395,7 +392,7 @@ impl<T> fmt::Display for Box<T>
where where
T: fmt::Display, T: fmt::Display,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<T as fmt::Display>::fmt(self, f) <T as fmt::Display>::fmt(self, f)
} }
} }
@ -454,13 +451,8 @@ mod tests {
fn grow() { fn grow() {
static mut MEMORY: [u8; 1024] = [0; 1024]; static mut MEMORY: [u8; 1024] = [0; 1024];
#[cfg(feature = "min-const-fn")]
static POOL: Pool<[u8; 128]> = Pool::new(); static POOL: Pool<[u8; 128]> = Pool::new();
#[allow(non_snake_case)]
#[cfg(not(feature = "min-const-fn"))]
let POOL: Pool<[u8; 128]> = Pool::new();
unsafe { unsafe {
POOL.grow(&mut MEMORY); POOL.grow(&mut MEMORY);
} }
@ -474,13 +466,8 @@ mod tests {
fn sanity() { fn sanity() {
static mut MEMORY: [u8; 31] = [0; 31]; static mut MEMORY: [u8; 31] = [0; 31];
#[cfg(feature = "min-const-fn")]
static POOL: Pool<u8> = Pool::new(); static POOL: Pool<u8> = Pool::new();
#[allow(non_snake_case)]
#[cfg(not(feature = "min-const-fn"))]
let POOL: Pool<u8> = Pool::new();
// empty pool // empty pool
assert!(POOL.alloc().is_none()); assert!(POOL.alloc().is_none());
@ -519,13 +506,8 @@ mod tests {
static mut MEMORY: [u8; 31] = [0; 31]; static mut MEMORY: [u8; 31] = [0; 31];
#[cfg(feature = "min-const-fn")]
static POOL: Pool<X> = Pool::new(); static POOL: Pool<X> = Pool::new();
#[allow(non_snake_case)]
#[cfg(not(feature = "min-const-fn"))]
let POOL: Pool<X> = Pool::new();
POOL.grow(unsafe { &mut MEMORY }); POOL.grow(unsafe { &mut MEMORY });
let x = POOL.alloc().unwrap().init(X::new()); let x = POOL.alloc().unwrap().init(X::new());

View File

@ -15,7 +15,7 @@ use as_slice::{AsMutSlice, AsSlice};
use super::{Init, Uninit}; use super::{Init, Uninit};
/// Instantiates a pool as a global singleton /// Instantiates a pool as a global singleton
#[cfg(all(any(armv7m, test), feature = "min-const-fn"))] #[cfg(any(armv7m, test))]
#[macro_export] #[macro_export]
macro_rules! pool { macro_rules! pool {
($ident:ident: $ty:ty) => { ($ident:ident: $ty:ty) => {
@ -153,7 +153,7 @@ where
P: Pool, P: Pool,
P::Data: fmt::Debug, P::Data: fmt::Debug,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<P::Data as fmt::Debug>::fmt(self, f) <P::Data as fmt::Debug>::fmt(self, f)
} }
} }
@ -163,7 +163,7 @@ where
P: Pool, P: Pool,
P::Data: fmt::Display, P::Data: fmt::Display,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<P::Data as fmt::Display>::fmt(self, f) <P::Data as fmt::Display>::fmt(self, f)
} }
} }
@ -270,7 +270,7 @@ where
} }
} }
#[cfg(all(test, feature = "min-const-fn"))] #[cfg(test)]
mod tests { mod tests {
use core::{ use core::{
mem, mem,

View File

@ -1,8 +1,6 @@
use core::sync::atomic::{self, AtomicUsize, Ordering}; use core::sync::atomic::{self, AtomicU16, AtomicU8, AtomicUsize, Ordering};
#[cfg(feature = "smaller-atomics")]
use core::sync::atomic::{AtomicU16, AtomicU8};
use spsc::{MultiCore, SingleCore}; use crate::spsc::{MultiCore, SingleCore};
pub unsafe trait XCore { pub unsafe trait XCore {
fn is_multi_core() -> bool; fn is_multi_core() -> bool;
@ -38,7 +36,6 @@ pub unsafe trait Uxx: Into<usize> + Send {
C: XCore; C: XCore;
} }
#[cfg(feature = "smaller-atomics")]
unsafe impl Uxx for u8 { unsafe impl Uxx for u8 {
fn truncate(x: usize) -> Self { fn truncate(x: usize) -> Self {
let max = ::core::u8::MAX; let max = ::core::u8::MAX;
@ -79,7 +76,6 @@ unsafe impl Uxx for u8 {
} }
} }
#[cfg(feature = "smaller-atomics")]
unsafe impl Uxx for u16 { unsafe impl Uxx for u16 {
fn truncate(x: usize) -> Self { fn truncate(x: usize) -> Self {
let max = ::core::u16::MAX; let max = ::core::u16::MAX;

View File

@ -1,16 +1,12 @@
use hash32::{BuildHasher, Hash};
use generic_array::{typenum::PowerOfTwo, ArrayLength}; use generic_array::{typenum::PowerOfTwo, ArrayLength};
use hash32::{BuildHasher, Hash};
use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
use super::binary_heap::Kind as BinaryHeapKind; use crate::{
use super::indexmap::{Bucket, Pos}; binary_heap::Kind as BinaryHeapKind,
use BinaryHeap; indexmap::{Bucket, Pos},
use IndexMap; BinaryHeap, IndexMap, IndexSet, LinearMap, String, Vec,
use IndexSet; };
use LinearMap;
use String;
use Vec;
// Sequential containers // Sequential containers

View File

@ -1,15 +1,12 @@
//! Single producer single consumer queue //! Single producer single consumer queue
use core::cell::UnsafeCell; use core::{cell::UnsafeCell, fmt, hash, marker::PhantomData, mem::MaybeUninit, ptr};
use core::marker::PhantomData;
use core::{ptr, fmt, hash};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use hash32; use hash32;
pub use self::split::{Consumer, Producer}; use crate::sealed;
use __core::mem::MaybeUninit; pub use split::{Consumer, Producer};
use sealed;
mod split; mod split;
@ -176,7 +173,7 @@ where
} }
/// Iterates from the front of the queue to the back /// Iterates from the front of the queue to the back
pub fn iter(&self) -> Iter<T, N, U, C> { pub fn iter(&self) -> Iter<'_, T, N, U, C> {
Iter { Iter {
rb: self, rb: self,
index: 0, index: 0,
@ -185,7 +182,7 @@ where
} }
/// Returns an iterator that allows modifying each value. /// Returns an iterator that allows modifying each value.
pub fn iter_mut(&mut self) -> IterMut<T, N, U, C> { pub fn iter_mut(&mut self) -> IterMut<'_, T, N, U, C> {
let len = self.len_usize(); let len = self.len_usize();
IterMut { IterMut {
rb: self, rb: self,
@ -224,7 +221,7 @@ where
U: sealed::Uxx, U: sealed::Uxx,
C: sealed::XCore, C: sealed::XCore,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter()).finish() f.debug_list().entries(self.iter()).finish()
} }
} }
@ -259,7 +256,6 @@ where
} }
} }
impl<'a, T, N, U, C> IntoIterator for &'a Queue<T, N, U, C> impl<'a, T, N, U, C> IntoIterator for &'a Queue<T, N, U, C>
where where
N: ArrayLength<T>, N: ArrayLength<T>,
@ -298,7 +294,7 @@ macro_rules! impl_ {
/// Creates an empty queue with a fixed capacity of `N` /// Creates an empty queue with a fixed capacity of `N`
pub const fn $uxx() -> Self { pub const fn $uxx() -> Self {
Queue { Queue {
buffer: unsafe { MaybeUninit::uninitialized() }, buffer: MaybeUninit::uninit(),
head: Atomic::new(0), head: Atomic::new(0),
tail: Atomic::new(0), tail: Atomic::new(0),
} }
@ -314,7 +310,7 @@ macro_rules! impl_ {
/// Creates an empty queue with a fixed capacity of `N` (single core variant) /// Creates an empty queue with a fixed capacity of `N` (single core variant)
pub const unsafe fn $uxx_sc() -> Self { pub const unsafe fn $uxx_sc() -> Self {
Queue { Queue {
buffer: MaybeUninit::uninitialized(), buffer: MaybeUninit::uninit(),
head: Atomic::new(0), head: Atomic::new(0),
tail: Atomic::new(0), tail: Atomic::new(0),
} }
@ -334,10 +330,10 @@ macro_rules! impl_ {
let head = self.head.get_mut(); let head = self.head.get_mut();
let tail = self.tail.get_mut(); let tail = self.tail.get_mut();
let buffer = unsafe { self.buffer.get_ref() }; let p = self.buffer.as_ptr();
if *head != *tail { if *head != *tail {
let item = unsafe { ptr::read(buffer.get_unchecked(usize::from(*head % cap))) }; let item = unsafe { (p as *const T).add(usize::from(*head % cap)).read() };
*head = head.wrapping_add(1); *head = head.wrapping_add(1);
Some(item) Some(item)
} else { } else {
@ -373,12 +369,12 @@ macro_rules! impl_ {
let cap = self.capacity(); let cap = self.capacity();
let tail = self.tail.get_mut(); let tail = self.tail.get_mut();
let buffer = self.buffer.get_mut();
// NOTE(ptr::write) the memory slot that we are about to write to is // NOTE(ptr::write) the memory slot that we are about to write to is
// uninitialized. We use `ptr::write` to avoid running `T`'s destructor on the // uninitialized. We use `ptr::write` to avoid running `T`'s destructor on the
// uninitialized memory // uninitialized memory
ptr::write(buffer.get_unchecked_mut(usize::from(*tail % cap)), item); (self.buffer.as_mut_ptr() as *mut T)
.add(usize::from(*tail % cap))
.write(item);
*tail = tail.wrapping_add(1); *tail = tail.wrapping_add(1);
} }
@ -403,7 +399,7 @@ macro_rules! impl_ {
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
let mut new: Queue<T, N, $uxx, C> = Queue { let mut new: Queue<T, N, $uxx, C> = Queue {
buffer: unsafe { MaybeUninit::uninitialized() }, buffer: MaybeUninit::uninit(),
head: Atomic::new(0), head: Atomic::new(0),
tail: Atomic::new(0), tail: Atomic::new(0),
}; };
@ -417,7 +413,6 @@ macro_rules! impl_ {
new new
} }
} }
}; };
} }
@ -445,9 +440,7 @@ where
} }
} }
#[cfg(feature = "smaller-atomics")]
impl_!(u8, u8_sc); impl_!(u8, u8_sc);
#[cfg(feature = "smaller-atomics")]
impl_!(u16, u16_sc); impl_!(u16, u16_sc);
impl_!(usize, usize_sc); impl_!(usize, usize_sc);
@ -463,10 +456,7 @@ where
{ {
fn eq(&self, other: &Queue<T, N2, U2, C2>) -> bool { fn eq(&self, other: &Queue<T, N2, U2, C2>) -> bool {
self.len_usize() == other.len_usize() self.len_usize() == other.len_usize()
&& self && self.iter().zip(other.iter()).all(|(v1, v2)| v1 == v2)
.iter()
.zip(other.iter())
.all(|(v1, v2)| v1 == v2)
} }
} }
@ -477,16 +467,14 @@ where
U: sealed::Uxx, U: sealed::Uxx,
C: sealed::XCore, C: sealed::XCore,
{ {
} }
/// An iterator over the items of a queue /// An iterator over the items of a queue
pub struct Iter<'a, T, N, U, C> pub struct Iter<'a, T, N, U, C>
where where
N: ArrayLength<T> + 'a, N: ArrayLength<T>,
T: 'a, U: sealed::Uxx,
U: 'a + sealed::Uxx, C: sealed::XCore,
C: 'a + sealed::XCore,
{ {
rb: &'a Queue<T, N, U, C>, rb: &'a Queue<T, N, U, C>,
index: usize, index: usize,
@ -495,10 +483,9 @@ where
impl<'a, T, N, U, C> Clone for Iter<'a, T, N, U, C> impl<'a, T, N, U, C> Clone for Iter<'a, T, N, U, C>
where where
N: ArrayLength<T> + 'a, N: ArrayLength<T>,
T: 'a, U: sealed::Uxx,
U: 'a + sealed::Uxx, C: sealed::XCore,
C: 'a + sealed::XCore,
{ {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
@ -512,10 +499,9 @@ where
/// A mutable iterator over the items of a queue /// A mutable iterator over the items of a queue
pub struct IterMut<'a, T, N, U, C> pub struct IterMut<'a, T, N, U, C>
where where
N: ArrayLength<T> + 'a, N: ArrayLength<T>,
T: 'a, U: sealed::Uxx,
U: 'a + sealed::Uxx, C: sealed::XCore,
C: 'a + sealed::XCore,
{ {
rb: &'a mut Queue<T, N, U, C>, rb: &'a mut Queue<T, N, U, C>,
index: usize, index: usize,
@ -523,13 +509,12 @@ where
} }
macro_rules! iterator { macro_rules! iterator {
(struct $name:ident -> $elem:ty, $ptr:ty, $asref:ident, $asptr:ident, $mkref:ident) => { (struct $name:ident -> $elem:ty, $ptr:ty, $asptr:ident, $mkref:ident) => {
impl<'a, T, N, U, C> Iterator for $name<'a, T, N, U, C> impl<'a, T, N, U, C> Iterator for $name<'a, T, N, U, C>
where where
N: ArrayLength<T>, N: ArrayLength<T>,
T: 'a, U: sealed::Uxx,
U: 'a + sealed::Uxx, C: sealed::XCore,
C: 'a + sealed::XCore,
{ {
type Item = $elem; type Item = $elem;
@ -538,8 +523,7 @@ macro_rules! iterator {
let head = self.rb.head.load_relaxed().into(); let head = self.rb.head.load_relaxed().into();
let cap = self.rb.capacity().into(); let cap = self.rb.capacity().into();
let buffer = unsafe { self.rb.buffer.$asref() }; let ptr = self.rb.buffer.$asptr() as $ptr;
let ptr: $ptr = buffer.$asptr();
let i = (head + self.index) % cap; let i = (head + self.index) % cap;
self.index += 1; self.index += 1;
Some(unsafe { $mkref!(*ptr.offset(i as isize)) }) Some(unsafe { $mkref!(*ptr.offset(i as isize)) })
@ -563,15 +547,15 @@ macro_rules! make_ref_mut {
}; };
} }
iterator!(struct Iter -> &'a T, *const T, get_ref, as_ptr, make_ref); iterator!(struct Iter -> &'a T, *const T, as_ptr, make_ref);
iterator!(struct IterMut -> &'a mut T, *mut T, get_mut, as_mut_ptr, make_ref_mut); iterator!(struct IterMut -> &'a mut T, *mut T, as_mut_ptr, make_ref_mut);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use consts::*;
use spsc::Queue;
use hash32::Hasher; use hash32::Hasher;
use crate::{consts::*, spsc::Queue};
#[cfg(feature = "const-fn")] #[cfg(feature = "const-fn")]
#[test] #[test]
fn static_new() { fn static_new() {
@ -741,11 +725,7 @@ mod tests {
let rb2 = rb1.clone(); let rb2 = rb1.clone();
assert_eq!(rb1.capacity(), rb2.capacity()); assert_eq!(rb1.capacity(), rb2.capacity());
assert_eq!(rb1.len_usize(), rb2.len_usize()); assert_eq!(rb1.len_usize(), rb2.len_usize());
assert!( assert!(rb1.iter().zip(rb2.iter()).all(|(v1, v2)| v1 == v2));
rb1.iter()
.zip(rb2.iter())
.all(|(v1, v2)| v1 == v2)
);
} }
#[test] #[test]

View File

@ -1,10 +1,11 @@
use core::marker::PhantomData; use core::{marker::PhantomData, ptr::NonNull};
use core::ptr::{self, NonNull};
use generic_array::ArrayLength; use generic_array::ArrayLength;
use sealed; use crate::{
use spsc::{MultiCore, Queue}; sealed,
spsc::{MultiCore, Queue},
};
impl<T, N, U, C> Queue<T, N, U, C> impl<T, N, U, C> Queue<T, N, U, C>
where where
@ -110,9 +111,10 @@ macro_rules! impl_ {
let rb = self.rb.as_ref(); let rb = self.rb.as_ref();
let cap = rb.capacity(); let cap = rb.capacity();
let buffer = rb.buffer.get_ref();
let item = ptr::read(buffer.get_unchecked(usize::from(head % cap))); let item = (rb.buffer.as_ptr() as *const T)
.add(usize::from(head % cap))
.read();
rb.head.store_release(head.wrapping_add(1)); // ▲ rb.head.store_release(head.wrapping_add(1)); // ▲
item item
} }
@ -177,28 +179,26 @@ macro_rules! impl_ {
let rb = self.rb.as_mut(); let rb = self.rb.as_mut();
let cap = rb.capacity(); let cap = rb.capacity();
let buffer = rb.buffer.get_mut();
// NOTE(ptr::write) the memory slot that we are about to write to is // NOTE(ptr::write) the memory slot that we are about to write to is
// uninitialized. We use `ptr::write` to avoid running `T`'s destructor on the // uninitialized. We use `ptr::write` to avoid running `T`'s destructor on the
// uninitialized memory // uninitialized memory
ptr::write(buffer.get_unchecked_mut(usize::from(tail % cap)), item); (rb.buffer.as_mut_ptr() as *mut T)
.add(usize::from(tail % cap))
.write(item);
rb.tail.store_release(tail.wrapping_add(1)); // ▲ rb.tail.store_release(tail.wrapping_add(1)); // ▲
} }
} }
}; };
} }
#[cfg(feature = "smaller-atomics")]
impl_!(u8); impl_!(u8);
#[cfg(feature = "smaller-atomics")]
impl_!(u16); impl_!(u16);
impl_!(usize); impl_!(usize);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use consts::*; use crate::{consts::*, spsc::Queue};
use spsc::Queue;
#[test] #[test]
fn sanity() { fn sanity() {

View File

@ -1,15 +1,12 @@
use core::fmt::Write; use core::{fmt, fmt::Write, hash, ops, str, str::Utf8Error};
use core::str::Utf8Error;
use core::{fmt, hash, ops, str};
use hash32;
use generic_array::{ use generic_array::{
typenum::{consts::*, IsGreaterOrEqual}, typenum::{consts::*, IsGreaterOrEqual},
ArrayLength, ArrayLength,
}; };
use hash32;
use Vec; use crate::Vec;
/// 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)
pub struct String<N> pub struct String<N>
@ -444,7 +441,7 @@ impl<N> fmt::Debug for String<N>
where where
N: ArrayLength<u8>, N: ArrayLength<u8>,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let slice: &str = &**self; let slice: &str = &**self;
fmt::Debug::fmt(slice, f) fmt::Debug::fmt(slice, f)
} }
@ -454,7 +451,7 @@ impl<N> fmt::Display for String<N>
where where
N: ArrayLength<u8>, N: ArrayLength<u8>,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let slice: &str = &**self; let slice: &str = &**self;
fmt::Display::fmt(slice, f) fmt::Display::fmt(slice, f)
} }
@ -611,8 +608,7 @@ impl_from_num!(u64, U20);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use consts::*; use crate::{consts::*, String, Vec};
use {String, Vec};
#[cfg(feature = "const-fn")] #[cfg(feature = "const-fn")]
#[test] #[test]
@ -632,8 +628,6 @@ mod tests {
#[test] #[test]
fn debug() { fn debug() {
extern crate std;
use core::fmt::Write; use core::fmt::Write;
let s: String<U8> = String::from("abcd"); let s: String<U8> = String::from("abcd");
@ -644,8 +638,6 @@ mod tests {
#[test] #[test]
fn display() { fn display() {
extern crate std;
use core::fmt::Write; use core::fmt::Write;
let s: String<U8> = String::from("abcd"); let s: String<U8> = String::from("abcd");

View File

@ -1,13 +1,8 @@
use core::{fmt, ops, ptr, slice}; use core::{fmt, hash, iter::FromIterator, mem::MaybeUninit, ops, ptr, slice};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use hash32; use hash32;
use __core::mem::MaybeUninit;
use core::hash;
use core::iter::FromIterator;
/// 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 /// # Examples
@ -66,7 +61,7 @@ where
/// Constructs a new, empty vector with a fixed capacity of `N` /// Constructs a new, empty vector with a fixed capacity of `N`
pub const fn new() -> Self { pub const fn new() -> Self {
Vec { Vec {
buffer: unsafe { MaybeUninit::uninitialized() }, buffer: MaybeUninit::uninit(),
len: 0, len: 0,
} }
} }
@ -126,11 +121,8 @@ where
pub(crate) unsafe fn pop_unchecked(&mut self) -> T { pub(crate) unsafe fn pop_unchecked(&mut self) -> T {
debug_assert!(!self.is_empty()); debug_assert!(!self.is_empty());
let buffer = self.buffer.get_ref();
self.len -= 1; self.len -= 1;
let item = ptr::read(buffer.get_unchecked(self.len)); (self.buffer.as_ptr() as *const T).add(self.len).read()
item
} }
/// Appends an `item` to the back of the collection /// Appends an `item` to the back of the collection
@ -146,11 +138,12 @@ where
} }
pub(crate) unsafe fn push_unchecked(&mut self, item: T) { pub(crate) unsafe fn push_unchecked(&mut self, item: T) {
let buffer = self.buffer.get_mut();
// NOTE(ptr::write) the memory slot that we are about to write to is uninitialized. We // NOTE(ptr::write) the memory slot that we are about to write to is uninitialized. We
// use `ptr::write` to avoid running `T`'s destructor on the uninitialized memory // use `ptr::write` to avoid running `T`'s destructor on the uninitialized memory
ptr::write(buffer.get_unchecked_mut(self.len), item); (self.buffer.as_mut_ptr() as *mut T)
.add(self.len)
.write(item);
self.len += 1; self.len += 1;
} }
@ -271,7 +264,7 @@ where
T: fmt::Debug, T: fmt::Debug,
N: ArrayLength<T>, N: ArrayLength<T>,
{ {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let slice: &[T] = &**self; let slice: &[T] = &**self;
slice.fmt(f) slice.fmt(f)
} }
@ -394,8 +387,7 @@ where
type Item = T; type Item = T;
fn next(&mut self) -> Option<Self::Item> { fn next(&mut self) -> Option<Self::Item> {
if self.next < self.vec.len() { if self.next < self.vec.len() {
let buffer = unsafe { self.vec.buffer.get_ref() }; let item = unsafe { (self.vec.buffer.as_ptr() as *const T).add(self.next).read() };
let item = unsafe { ptr::read(buffer.get_unchecked(self.next)) };
self.next += 1; self.next += 1;
Some(item) Some(item)
} else { } else {
@ -500,10 +492,9 @@ where
type Target = [T]; type Target = [T];
fn deref(&self) -> &[T] { fn deref(&self) -> &[T] {
let buffer = unsafe { self.buffer.get_ref() };
// NOTE(unsafe) avoid bound checks in the slicing operation // NOTE(unsafe) avoid bound checks in the slicing operation
// &buffer[..self.len] // &buffer[..self.len]
unsafe { slice::from_raw_parts(buffer.as_ptr(), self.len) } unsafe { slice::from_raw_parts(self.buffer.as_ptr() as *const T, self.len) }
} }
} }
@ -513,11 +504,10 @@ where
{ {
fn deref_mut(&mut self) -> &mut [T] { fn deref_mut(&mut self) -> &mut [T] {
let len = self.len(); let len = self.len();
let buffer = unsafe { self.buffer.get_mut() };
// NOTE(unsafe) avoid bound checks in the slicing operation // NOTE(unsafe) avoid bound checks in the slicing operation
// &mut buffer[..len] // &mut buffer[..len]
unsafe { slice::from_raw_parts_mut(buffer.as_mut_ptr(), len) } unsafe { slice::from_raw_parts_mut(self.buffer.as_mut_ptr() as *mut T, len) }
} }
} }
@ -563,8 +553,7 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use consts::*; use crate::{consts::*, Vec};
use Vec;
#[cfg(feature = "const-fn")] #[cfg(feature = "const-fn")]
#[test] #[test]