diff --git a/Cargo.toml b/Cargo.toml index 0c45a6d0..3a1d1d8b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,7 @@ stable_deref_trait = { version = "1", default-features = false } [dev-dependencies] ufmt = "0.2" +static_assertions = "1.1.0" [package.metadata.docs.rs] features = ["ufmt", "serde", "defmt-03", "mpmc_large", "portable-atomic-critical-section"] diff --git a/cfail/ui/not-send.rs b/cfail/ui/not-send.rs deleted file mode 100644 index 0c8559d9..00000000 --- a/cfail/ui/not-send.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! Collections of non-`Send`-able things are *not* `Send` - -use core::marker::PhantomData; - -use heapless::{ - spsc::{Consumer, Producer, Queue}, - HistoryBuffer, Vec, -}; - -type NotSend = PhantomData<*const ()>; - -fn is_send() -where - T: Send, -{ -} - -fn main() { - is_send::>(); - is_send::>(); - is_send::>(); - is_send::>(); - is_send::>(); -} diff --git a/cfail/ui/not-send.stderr b/cfail/ui/not-send.stderr deleted file mode 100644 index c4985b8b..00000000 --- a/cfail/ui/not-send.stderr +++ /dev/null @@ -1,159 +0,0 @@ -error[E0277]: `*const ()` cannot be sent between threads safely - --> ui/not-send.rs:19:15 - | -19 | is_send::>(); - | ^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely - | - = help: within `PhantomData<*const ()>`, the trait `Send` is not implemented for `*const ()` -note: required because it appears within the type `PhantomData<*const ()>` - --> $RUST/core/src/marker.rs - | - | pub struct PhantomData; - | ^^^^^^^^^^^ - = note: required for `Consumer<'_, PhantomData<*const ()>, 4>` to implement `Send` -note: required by a bound in `is_send` - --> ui/not-send.rs:14:8 - | -12 | fn is_send() - | ------- required by a bound in this function -13 | where -14 | T: Send, - | ^^^^ required by this bound in `is_send` - -error[E0277]: `*const ()` cannot be sent between threads safely - --> ui/not-send.rs:20:15 - | -20 | is_send::>(); - | ^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely - | - = help: within `PhantomData<*const ()>`, the trait `Send` is not implemented for `*const ()` -note: required because it appears within the type `PhantomData<*const ()>` - --> $RUST/core/src/marker.rs - | - | pub struct PhantomData; - | ^^^^^^^^^^^ - = note: required for `Producer<'_, PhantomData<*const ()>, 4>` to implement `Send` -note: required by a bound in `is_send` - --> ui/not-send.rs:14:8 - | -12 | fn is_send() - | ------- required by a bound in this function -13 | where -14 | T: Send, - | ^^^^ required by this bound in `is_send` - -error[E0277]: `*const ()` cannot be sent between threads safely - --> ui/not-send.rs:21:15 - | -21 | is_send::>(); - | ^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely - | - = help: within `Queue, 4>`, the trait `Send` is not implemented for `*const ()` -note: required because it appears within the type `PhantomData<*const ()>` - --> $RUST/core/src/marker.rs - | - | pub struct PhantomData; - | ^^^^^^^^^^^ -note: required because it appears within the type `ManuallyDrop>` - --> $RUST/core/src/mem/manually_drop.rs - | - | pub struct ManuallyDrop { - | ^^^^^^^^^^^^ -note: required because it appears within the type `MaybeUninit>` - --> $RUST/core/src/mem/maybe_uninit.rs - | - | pub union MaybeUninit { - | ^^^^^^^^^^^ -note: required because it appears within the type `UnsafeCell>>` - --> $RUST/core/src/cell.rs - | - | pub struct UnsafeCell { - | ^^^^^^^^^^ - = note: required because it appears within the type `[UnsafeCell>>; 4]` -note: required because it appears within the type `Queue, 4>` - --> $HEAPLESS/src/spsc.rs - | - | pub struct Queue { - | ^^^^^ -note: required by a bound in `is_send` - --> ui/not-send.rs:14:8 - | -12 | fn is_send() - | ------- required by a bound in this function -13 | where -14 | T: Send, - | ^^^^ required by this bound in `is_send` - -error[E0277]: `*const ()` cannot be sent between threads safely - --> ui/not-send.rs:22:15 - | -22 | is_send::>(); - | ^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely - | - = help: within `heapless::vec::VecInner<[MaybeUninit>; 4]>`, the trait `Send` is not implemented for `*const ()` -note: required because it appears within the type `PhantomData<*const ()>` - --> $RUST/core/src/marker.rs - | - | pub struct PhantomData; - | ^^^^^^^^^^^ -note: required because it appears within the type `ManuallyDrop>` - --> $RUST/core/src/mem/manually_drop.rs - | - | pub struct ManuallyDrop { - | ^^^^^^^^^^^^ -note: required because it appears within the type `MaybeUninit>` - --> $RUST/core/src/mem/maybe_uninit.rs - | - | pub union MaybeUninit { - | ^^^^^^^^^^^ - = note: required because it appears within the type `[MaybeUninit>; 4]` -note: required because it appears within the type `heapless::vec::VecInner<[MaybeUninit>; 4]>` - --> $HEAPLESS/src/vec.rs - | - | pub struct VecInner { - | ^^^^^^^^ -note: required by a bound in `is_send` - --> ui/not-send.rs:14:8 - | -12 | fn is_send() - | ------- required by a bound in this function -13 | where -14 | T: Send, - | ^^^^ required by this bound in `is_send` - -error[E0277]: `*const ()` cannot be sent between threads safely - --> ui/not-send.rs:23:15 - | -23 | is_send::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely - | - = help: within `HistoryBuffer, 4>`, the trait `Send` is not implemented for `*const ()` -note: required because it appears within the type `PhantomData<*const ()>` - --> $RUST/core/src/marker.rs - | - | pub struct PhantomData; - | ^^^^^^^^^^^ -note: required because it appears within the type `ManuallyDrop>` - --> $RUST/core/src/mem/manually_drop.rs - | - | pub struct ManuallyDrop { - | ^^^^^^^^^^^^ -note: required because it appears within the type `MaybeUninit>` - --> $RUST/core/src/mem/maybe_uninit.rs - | - | pub union MaybeUninit { - | ^^^^^^^^^^^ - = note: required because it appears within the type `[MaybeUninit>; 4]` -note: required because it appears within the type `HistoryBuffer, 4>` - --> $HEAPLESS/src/histbuf.rs - | - | pub struct HistoryBuffer { - | ^^^^^^^^^^^^^ -note: required by a bound in `is_send` - --> ui/not-send.rs:14:8 - | -12 | fn is_send() - | ------- required by a bound in this function -13 | where -14 | T: Send, - | ^^^^ required by this bound in `is_send` diff --git a/src/deque.rs b/src/deque.rs index c19369b2..9e923539 100644 --- a/src/deque.rs +++ b/src/deque.rs @@ -745,7 +745,12 @@ where #[cfg(test)] mod tests { - use crate::Deque; + use static_assertions::assert_not_impl_any; + + use super::Deque; + + // Ensure a `Deque` containing `!Send` values stays `!Send` itself. + assert_not_impl_any!(Deque<*const (), 4>: Send); #[test] fn static_new() { diff --git a/src/histbuf.rs b/src/histbuf.rs index 45d94622..98f75561 100644 --- a/src/histbuf.rs +++ b/src/histbuf.rs @@ -433,10 +433,16 @@ impl<'a, T, const N: usize> Iterator for OldestOrdered<'a, T, N> { #[cfg(test)] mod tests { - use crate::HistoryBuffer; use core::fmt::Debug; use core::sync::atomic::{AtomicUsize, Ordering}; + use static_assertions::assert_not_impl_any; + + use super::HistoryBuffer; + + // Ensure a `HistoryBuffer` containing `!Send` values stays `!Send` itself. + assert_not_impl_any!(HistoryBuffer<*const (), 4>: Send); + #[test] fn new() { let x: HistoryBuffer = HistoryBuffer::new_with(1); diff --git a/src/indexmap.rs b/src/indexmap.rs index bd07a56e..957d81c5 100644 --- a/src/indexmap.rs +++ b/src/indexmap.rs @@ -1262,10 +1262,17 @@ where #[cfg(test)] mod tests { - use crate::{indexmap::Entry, FnvIndexMap}; - use core::mem; + use static_assertions::assert_not_impl_any; + + use super::{BuildHasherDefault, Entry, FnvIndexMap, IndexMap}; + + // Ensure a `IndexMap` containing `!Send` keys stays `!Send` itself. + assert_not_impl_any!(IndexMap<*const (), (), BuildHasherDefault<()>, 4>: Send); + // Ensure a `IndexMap` containing `!Send` values stays `!Send` itself. + assert_not_impl_any!(IndexMap<(), *const (), BuildHasherDefault<()>, 4>: Send); + #[test] fn size() { const CAP: usize = 4; diff --git a/src/indexset.rs b/src/indexset.rs index 04607e68..17b970ab 100644 --- a/src/indexset.rs +++ b/src/indexset.rs @@ -1,11 +1,13 @@ -use crate::indexmap::{self, IndexMap}; use core::{ borrow::Borrow, fmt, hash::{BuildHasher, Hash}, }; + use hash32::{BuildHasherDefault, FnvHasher}; +use crate::indexmap::{self, IndexMap}; + /// An [`IndexSet`] using the default FNV hasher. /// /// A list of all Methods and Traits available for `FnvIndexSet` can be found in @@ -659,3 +661,13 @@ where } } } + +#[cfg(test)] +mod tests { + use static_assertions::assert_not_impl_any; + + use super::{BuildHasherDefault, IndexSet}; + + // Ensure a `IndexSet` containing `!Send` values stays `!Send` itself. + assert_not_impl_any!(IndexSet<*const (), BuildHasherDefault<()>, 4>: Send); +} diff --git a/src/linear_map.rs b/src/linear_map.rs index efdfe4f4..a7a07198 100644 --- a/src/linear_map.rs +++ b/src/linear_map.rs @@ -1,6 +1,7 @@ -use crate::Vec; use core::{borrow::Borrow, fmt, mem, ops, slice}; +use crate::Vec; + /// A fixed capacity map/dictionary that performs lookups via linear search. /// /// Note that as this map doesn't use hashing so most operations are *O*(n) instead of *O*(1). @@ -492,7 +493,14 @@ where #[cfg(test)] mod test { - use crate::LinearMap; + use static_assertions::assert_not_impl_any; + + use super::LinearMap; + + // Ensure a `LinearMap` containing `!Send` keys stays `!Send` itself. + assert_not_impl_any!(LinearMap<*const (), (), 4>: Send); + // Ensure a `LinearMap` containing `!Send` values stays `!Send` itself. + assert_not_impl_any!(LinearMap<(), *const (), 4>: Send); #[test] fn static_new() { diff --git a/src/mpmc.rs b/src/mpmc.rs index 578a6698..9b0b6feb 100644 --- a/src/mpmc.rs +++ b/src/mpmc.rs @@ -294,7 +294,12 @@ unsafe fn enqueue( #[cfg(test)] mod tests { - use super::Q2; + use static_assertions::assert_not_impl_any; + + use super::{MpMcQueue, Q2}; + + // Ensure a `MpMcQueue` containing `!Send` values stays `!Send` itself. + assert_not_impl_any!(MpMcQueue<*const (), 4>: Send); #[test] fn sanity() { diff --git a/src/sorted_linked_list.rs b/src/sorted_linked_list.rs index f4102bd0..64bcdd6b 100644 --- a/src/sorted_linked_list.rs +++ b/src/sorted_linked_list.rs @@ -743,8 +743,13 @@ where #[cfg(test)] mod tests { + use static_assertions::assert_not_impl_any; + use super::*; + // Ensure a `SortedLinkedList` containing `!Send` values stays `!Send` itself. + assert_not_impl_any!(SortedLinkedList<*const (), LinkedIndexU8, (), 4>: Send); + #[test] fn const_new() { static mut _V1: SortedLinkedList = SortedLinkedList::new_u8(); diff --git a/src/spsc.rs b/src/spsc.rs index 3b9db75f..1b7ab035 100644 --- a/src/spsc.rs +++ b/src/spsc.rs @@ -632,7 +632,18 @@ impl<'a, T, const N: usize> Producer<'a, T, N> { mod tests { use std::hash::{Hash, Hasher}; - use crate::spsc::Queue; + use super::{Consumer, Producer, Queue}; + + use static_assertions::assert_not_impl_any; + + // Ensure a `Queue` containing `!Send` values stays `!Send` itself. + assert_not_impl_any!(Queue<*const (), 4>: Send); + + // Ensure a `Producer` containing `!Send` values stays `!Send` itself. + assert_not_impl_any!(Producer<*const (), 4>: Send); + + // Ensure a `Consumer` containing `!Send` values stays `!Send` itself. + assert_not_impl_any!(Consumer<*const (), 4>: Send); #[test] fn full() { diff --git a/src/vec.rs b/src/vec.rs index 0588f4d1..0361d41c 100644 --- a/src/vec.rs +++ b/src/vec.rs @@ -1,7 +1,6 @@ use core::{ cmp::Ordering, - fmt, hash, - mem, + fmt, hash, mem, mem::{ManuallyDrop, MaybeUninit}, ops, ptr, slice, }; @@ -2079,9 +2078,15 @@ where #[cfg(test)] mod tests { - use crate::Vec; use core::fmt::Write; + use static_assertions::assert_not_impl_any; + + use crate::Vec; + + // Ensure a `Vec` containing `!Send` values stays `!Send` itself. + assert_not_impl_any!(Vec<*const (), 4>: Send); + #[test] fn static_new() { static mut _V: Vec = Vec::new();