Skip to content

Fix several issues in const generics #199

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 5 commits into from
Mar 30, 2021
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
4 changes: 2 additions & 2 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ jobs:
toolchain:
- stable
- nightly
- 1.36.0
- 1.51.0
features:
- serde
buildtype:
Expand Down Expand Up @@ -242,7 +242,7 @@ jobs:
- name: Install Rust
uses: actions-rs/toolchain@v1
with:
toolchain: 1.36.0
toolchain: 1.51.0
target: x86_64-unknown-linux-gnu
override: true

Expand Down
4 changes: 2 additions & 2 deletions cfail/ui/freeze.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use heapless::{consts, spsc::Queue};
use heapless::{spsc::Queue};

fn main() {
let mut q: Queue<u8, consts::U4> = Queue::new();
let mut q: Queue<u8, _, _, 4> = Queue::new();

let (_p, mut _c) = q.split();
q.enqueue(0).unwrap();
Expand Down
9 changes: 4 additions & 5 deletions cfail/ui/not-send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
use core::marker::PhantomData;

use heapless::{
consts,
spsc::{Consumer, Producer, Queue},
};

Expand All @@ -16,8 +15,8 @@ where
}

fn main() {
is_send::<Consumer<NotSend, consts::U4>>();
is_send::<Producer<NotSend, consts::U4>>();
is_send::<Queue<NotSend, consts::U4>>();
is_send::<heapless::Vec<NotSend, consts::U4>>();
is_send::<Consumer<NotSend, _, _, 4>>();
is_send::<Producer<NotSend, _, _, 4>>();
is_send::<Queue<NotSend, _, _, 4>>();
is_send::<heapless::Vec<NotSend, 4>>();
}
122 changes: 54 additions & 68 deletions cfail/ui/not-send.stderr
Original file line number Diff line number Diff line change
@@ -1,83 +1,69 @@
error[E0277]: `*const ()` cannot be sent between threads safely
--> $DIR/not-send.rs:19:5
|
19 | is_send::<Consumer<NotSend, consts::U4>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely
--> $DIR/not-send.rs:18:5
|
= help: within `std::marker::PhantomData<*const ()>`, the trait `std::marker::Send` is not implemented for `*const ()`
= note: required because it appears within the type `std::marker::PhantomData<*const ()>`
= note: required because of the requirements on the impl of `std::marker::Send` for `heapless::spsc::split::Consumer<'_, std::marker::PhantomData<*const ()>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>`
note: required by `is_send`
--> $DIR/not-send.rs:12:1
11 | fn is_send<T>()
| ------- required by a bound in this
12 | where
13 | T: Send,
| ---- required by this bound in `is_send`
...
18 | is_send::<Consumer<NotSend, _, _, 4>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely
|
12 | / fn is_send<T>()
13 | | where
14 | | T: Send,
15 | | {
16 | | }
| |_^
= help: within `PhantomData<*const ()>`, the trait `Send` is not implemented for `*const ()`
= note: required because it appears within the type `PhantomData<*const ()>`
= note: required because of the requirements on the impl of `Send` for `Consumer<'_, PhantomData<*const ()>, _, _, 4_usize>`

error[E0277]: `*const ()` cannot be sent between threads safely
--> $DIR/not-send.rs:20:5
|
20 | is_send::<Producer<NotSend, consts::U4>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely
--> $DIR/not-send.rs:19:5
|
= help: within `std::marker::PhantomData<*const ()>`, the trait `std::marker::Send` is not implemented for `*const ()`
= note: required because it appears within the type `std::marker::PhantomData<*const ()>`
= note: required because of the requirements on the impl of `std::marker::Send` for `heapless::spsc::split::Producer<'_, std::marker::PhantomData<*const ()>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>`
note: required by `is_send`
--> $DIR/not-send.rs:12:1
11 | fn is_send<T>()
| ------- required by a bound in this
12 | where
13 | T: Send,
| ---- required by this bound in `is_send`
...
19 | is_send::<Producer<NotSend, _, _, 4>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely
|
12 | / fn is_send<T>()
13 | | where
14 | | T: Send,
15 | | {
16 | | }
| |_^
= help: within `PhantomData<*const ()>`, the trait `Send` is not implemented for `*const ()`
= note: required because it appears within the type `PhantomData<*const ()>`
= note: required because of the requirements on the impl of `Send` for `Producer<'_, PhantomData<*const ()>, _, _, 4_usize>`

error[E0277]: `*const ()` cannot be sent between threads safely
--> $DIR/not-send.rs:21:5
|
21 | is_send::<Queue<NotSend, consts::U4>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely
--> $DIR/not-send.rs:20:5
|
= help: within `std::marker::PhantomData<*const ()>`, the trait `std::marker::Send` is not implemented for `*const ()`
= note: required because it appears within the type `std::marker::PhantomData<*const ()>`
= note: required because of the requirements on the impl of `std::marker::Send` for `generic_array::GenericArray<std::marker::PhantomData<*const ()>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>`
= note: required because it appears within the type `std::mem::ManuallyDrop<generic_array::GenericArray<std::marker::PhantomData<*const ()>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>>`
= note: required because it appears within the type `std::mem::MaybeUninit<generic_array::GenericArray<std::marker::PhantomData<*const ()>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>>`
= note: required because it appears within the type `heapless::i::Queue<generic_array::GenericArray<std::marker::PhantomData<*const ()>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>>`
= note: required because it appears within the type `heapless::spsc::Queue<std::marker::PhantomData<*const ()>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>`
note: required by `is_send`
--> $DIR/not-send.rs:12:1
11 | fn is_send<T>()
| ------- required by a bound in this
12 | where
13 | T: Send,
| ---- required by this bound in `is_send`
...
20 | is_send::<Queue<NotSend, _, _, 4>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely
|
12 | / fn is_send<T>()
13 | | where
14 | | T: Send,
15 | | {
16 | | }
| |_^
= help: within `Queue<PhantomData<*const ()>, _, _, 4_usize>`, the trait `Send` is not implemented for `*const ()`
= note: required because it appears within the type `PhantomData<*const ()>`
= note: required because it appears within the type `[PhantomData<*const ()>; 4]`
= note: required because it appears within the type `ManuallyDrop<[PhantomData<*const ()>; 4]>`
= note: required because it appears within the type `MaybeUninit<[PhantomData<*const ()>; 4]>`
= note: required because it appears within the type `Queue<PhantomData<*const ()>, _, _, 4_usize>`

error[E0277]: `*const ()` cannot be sent between threads safely
--> $DIR/not-send.rs:22:5
|
22 | is_send::<heapless::Vec<NotSend, consts::U4>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely
--> $DIR/not-send.rs:21:5
|
= help: within `std::marker::PhantomData<*const ()>`, the trait `std::marker::Send` is not implemented for `*const ()`
= note: required because it appears within the type `std::marker::PhantomData<*const ()>`
= note: required because of the requirements on the impl of `std::marker::Send` for `generic_array::GenericArray<std::marker::PhantomData<*const ()>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>`
= note: required because it appears within the type `std::mem::ManuallyDrop<generic_array::GenericArray<std::marker::PhantomData<*const ()>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>>`
= note: required because it appears within the type `std::mem::MaybeUninit<generic_array::GenericArray<std::marker::PhantomData<*const ()>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>>`
= note: required because it appears within the type `heapless::i::Vec<generic_array::GenericArray<std::marker::PhantomData<*const ()>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>>`
= note: required because it appears within the type `heapless::vec::Vec<std::marker::PhantomData<*const ()>, typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UInt<typenum::uint::UTerm, typenum::bit::B1>, typenum::bit::B0>, typenum::bit::B0>>`
note: required by `is_send`
--> $DIR/not-send.rs:12:1
11 | fn is_send<T>()
| ------- required by a bound in this
12 | where
13 | T: Send,
| ---- required by this bound in `is_send`
...
21 | is_send::<heapless::Vec<NotSend, 4>>();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const ()` cannot be sent between threads safely
|
12 | / fn is_send<T>()
13 | | where
14 | | T: Send,
15 | | {
16 | | }
| |_^
= help: within `heapless::Vec<PhantomData<*const ()>, 4_usize>`, the trait `Send` is not implemented for `*const ()`
= note: required because it appears within the type `PhantomData<*const ()>`
= note: required because it appears within the type `[PhantomData<*const ()>; 4]`
= note: required because it appears within the type `ManuallyDrop<[PhantomData<*const ()>; 4]>`
= note: required because it appears within the type `MaybeUninit<[PhantomData<*const ()>; 4]>`
= note: required because it appears within the type `heapless::Vec<PhantomData<*const ()>, 4_usize>`
32 changes: 13 additions & 19 deletions src/de.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::{
sealed::binary_heap::Kind as BinaryHeapKind, BinaryHeap, IndexMap, IndexSet, LinearMap, String,
Vec,
};
use core::{fmt, marker::PhantomData};
use hash32::{BuildHasherDefault, Hash, Hasher};
use serde::de::{self, Deserialize, Deserializer, Error, MapAccess, SeqAccess};
use crate::{
sealed::binary_heap::Kind as BinaryHeapKind,
BinaryHeap, IndexMap, IndexSet, LinearMap, String, Vec,
};

// Sequential containers

Expand Down Expand Up @@ -142,9 +142,9 @@ where
where
D: Deserializer<'de>,
{
struct ValueVisitor<'de, K, V, S, const N:usize>(PhantomData<(&'de (), K, V, S)>);
struct ValueVisitor<'de, K, V, S, const N: usize>(PhantomData<(&'de (), K, V, S)>);

impl<'de, K, V, S, const N:usize> de::Visitor<'de> for ValueVisitor<'de, K, V, S, N>
impl<'de, K, V, S, const N: usize> de::Visitor<'de> for ValueVisitor<'de, K, V, S, N>
where
K: Eq + Hash + Deserialize<'de>,
V: Deserialize<'de>,
Expand Down Expand Up @@ -175,7 +175,7 @@ where
}
}

impl<'de, K, V, const N:usize> Deserialize<'de> for LinearMap<K, V, N>
impl<'de, K, V, const N: usize> Deserialize<'de> for LinearMap<K, V, N>
where
K: Eq + Deserialize<'de>,
V: Deserialize<'de>,
Expand All @@ -184,9 +184,9 @@ where
where
D: Deserializer<'de>,
{
struct ValueVisitor<'de, K, V, const N:usize>(PhantomData<(&'de (), K, V)>);
struct ValueVisitor<'de, K, V, const N: usize>(PhantomData<(&'de (), K, V)>);

impl<'de, K, V, const N:usize> de::Visitor<'de> for ValueVisitor<'de, K, V, N>
impl<'de, K, V, const N: usize> de::Visitor<'de> for ValueVisitor<'de, K, V, N>
where
K: Eq + Deserialize<'de>,
V: Deserialize<'de>,
Expand Down Expand Up @@ -218,24 +218,18 @@ where

// String containers

impl<'de, const N:usize> Deserialize<'de> for String<N>
{
impl<'de, const N: usize> Deserialize<'de> for String<N> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct ValueVisitor<'de, const N:usize>(PhantomData<&'de ()>);
struct ValueVisitor<'de, const N: usize>(PhantomData<&'de ()>);

impl<'de, const N:usize > de::Visitor<'de> for ValueVisitor<'de, N>
{
impl<'de, const N: usize> de::Visitor<'de> for ValueVisitor<'de, N> {
type Value = String<N>;

fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"a string no more than {} bytes long",
N as u64
)
write!(formatter, "a string no more than {} bytes long", N as u64)
}

fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
Expand Down
15 changes: 3 additions & 12 deletions src/indexmap.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
use core::{
borrow::Borrow,
fmt,
iter::FromIterator,
mem::{self, MaybeUninit},
num::NonZeroU32,
ops, slice,
};
use core::{borrow::Borrow, fmt, iter::FromIterator, mem, num::NonZeroU32, ops, slice};

use hash32::{BuildHasher, BuildHasherDefault, FnvHasher, Hash, Hasher};

Expand Down Expand Up @@ -126,14 +119,12 @@ macro_rules! probe_loop {
}
}

struct CoreMap<K, V, const N: usize>
{
struct CoreMap<K, V, const N: usize> {
entries: Vec<Bucket<K, V>, N>,
indices: [Option<Pos>; N],
}

impl<K, V, const N: usize> CoreMap<K, V, N>
{
impl<K, V, const N: usize> CoreMap<K, V, N> {
const fn new() -> Self {
const INIT: Option<Pos> = None;

Expand Down
2 changes: 2 additions & 0 deletions src/pool/singleton.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,14 @@ use as_slice::{AsMutSlice, AsSlice};
use super::{Init, Node, Uninit};

/// Instantiates a pool as a global singleton
// NOTE(any(test)) makes testing easier (no need to enable Cargo features for testing)
#[cfg(any(
armv7a,
armv7r,
armv7m,
armv8m_main,
all(target_arch = "x86_64", feature = "x86-sync-pool"),
test
))]
#[macro_export]
macro_rules! pool {
Expand Down
2 changes: 1 addition & 1 deletion src/ufmt.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use ufmt_write::uWrite;
use crate::{string::String, vec::Vec};
use ufmt_write::uWrite;

impl<const N: usize> uWrite for String<N> {
type Error = ();
Expand Down
2 changes: 1 addition & 1 deletion tests/cpass.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Collections of `Send`-able things are `Send`

use heapless::{
spsc::{Consumer, Producer, Queue, MultiCore},
spsc::{Consumer, MultiCore, Producer, Queue},
HistoryBuffer, Vec,
};

Expand Down
5 changes: 3 additions & 2 deletions tests/tsan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ fn unchecked() {
scope.execute(move || {
let mut sum: usize = 0;

for _ in 0..N/ 2 {
for _ in 0..N / 2 {
sum = sum.wrapping_add(usize::from(unsafe { c.dequeue_unchecked() }));
}

Expand All @@ -197,7 +197,7 @@ fn unchecked() {
});
}

assert_eq!(rb.len(), N/ 2);
assert_eq!(rb.len(), N / 2);
}

#[test]
Expand Down Expand Up @@ -235,6 +235,7 @@ fn iterator_properly_wraps() {
assert_eq!(expected, actual)
}

#[cfg(all(target_arch = "x86_64", feature = "x86-sync-pool"))]
#[test]
fn pool() {
use heapless::pool::singleton::Pool as _;
Expand Down