Merge branch 'master' into feature/historybuf_ordered_iterator

This commit is contained in:
Finn Bear 2022-01-15 23:34:01 -08:00 committed by GitHub
commit 4d0a160638
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 187 additions and 141 deletions

28
.github/workflows/changelog.yml vendored Normal file
View File

@ -0,0 +1,28 @@
# Check that the changelog is updated for all changes.
#
# This is only run for PRs.
on:
pull_request:
# opened, reopened, synchronize are the default types for pull_request.
# labeled, unlabeled ensure this check is also run if a label is added or removed.
types: [opened, reopened, labeled, unlabeled, synchronize]
name: Changelog
jobs:
changelog:
name: Changelog
runs-on: ubuntu-latest
steps:
- name: Checkout sources
uses: actions/checkout@v2
- name: Check that changelog updated
uses: dangoslen/changelog-enforcer@v3
with:
changeLogPath: CHANGELOG.md
skipLabels: 'needs-changelog, skip-changelog'
missingUpdateErrorMessage: 'Please add a changelog entry in the CHANGELOG.md file.'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -11,6 +11,19 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Added `OldestOrdered` iterator for `HistoryBuffer` - Added `OldestOrdered` iterator for `HistoryBuffer`
## [v0.7.9] - 2021-12-16
### Fixed
- Fix `IndexMap` and `IndexSet` bounds
- Make `IndexSet::new()` a `const fn`
## [v0.7.8] - 2021-11-11
### Added
- A span of `defmt` versions is now supported (`0.2` and `0.3`)
## [v0.7.7] - 2021-09-22 ## [v0.7.7] - 2021-09-22
### Fixed ### Fixed
@ -421,7 +434,9 @@ architecture.
- Initial release - Initial release
[Unreleased]: https://github.com/japaric/heapless/compare/v0.7.7...HEAD [Unreleased]: https://github.com/japaric/heapless/compare/v0.7.9...HEAD
[v0.7.9]: https://github.com/japaric/heapless/compare/v0.7.8...v0.7.9
[v0.7.8]: https://github.com/japaric/heapless/compare/v0.7.7...v0.7.8
[v0.7.7]: https://github.com/japaric/heapless/compare/v0.7.6...v0.7.7 [v0.7.7]: https://github.com/japaric/heapless/compare/v0.7.6...v0.7.7
[v0.7.6]: https://github.com/japaric/heapless/compare/v0.7.5...v0.7.6 [v0.7.6]: https://github.com/japaric/heapless/compare/v0.7.5...v0.7.6
[v0.7.5]: https://github.com/japaric/heapless/compare/v0.7.4...v0.7.5 [v0.7.5]: https://github.com/japaric/heapless/compare/v0.7.4...v0.7.5

View File

@ -12,7 +12,7 @@ keywords = ["static", "no-heap"]
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.7.7" version = "0.7.9"
[features] [features]
default = ["cas"] default = ["cas"]
@ -24,6 +24,7 @@ x86-sync-pool = []
__trybuild = [] __trybuild = []
# Enable larger MPMC sizes. # Enable larger MPMC sizes.
mpmc_large = [] mpmc_large = []
# This flag has no version guarantee, the `defmt` dependency can be updated in a patch release
defmt-impl = ["defmt"] defmt-impl = ["defmt"]
[target.'cfg(any(target_arch = "x86_64", target_arch = "x86"))'.dev-dependencies] [target.'cfg(any(target_arch = "x86_64", target_arch = "x86"))'.dev-dependencies]
@ -55,9 +56,5 @@ optional = true
version = "0.1" version = "0.1"
[dependencies.defmt] [dependencies.defmt]
version = "0.2.1" version = ">=0.2.0,<0.4"
optional = true optional = true
[dev-dependencies.defmt]
version = "0.2.1"
features = ["unstable-test"]

View File

@ -9,6 +9,7 @@
// n)` in-place heapsort. // n)` in-place heapsort.
use core::{ use core::{
cmp::Ordering,
fmt, fmt,
marker::PhantomData, marker::PhantomData,
mem::{self, ManuallyDrop}, mem::{self, ManuallyDrop},
@ -16,7 +17,6 @@ use core::{
ptr, slice, ptr, slice,
}; };
use crate::sealed::binary_heap::Kind;
use crate::vec::Vec; use crate::vec::Vec;
/// Min-heap /// Min-heap
@ -25,6 +25,32 @@ pub enum Min {}
/// Max-heap /// Max-heap
pub enum Max {} pub enum Max {}
/// The binary heap kind: min-heap or max-heap
pub trait Kind: private::Sealed {
#[doc(hidden)]
fn ordering() -> Ordering;
}
impl Kind for Min {
fn ordering() -> Ordering {
Ordering::Less
}
}
impl Kind for Max {
fn ordering() -> Ordering {
Ordering::Greater
}
}
/// Sealed traits
mod private {
pub trait Sealed {}
}
impl private::Sealed for Max {}
impl private::Sealed for Min {}
/// A priority queue implemented with a binary heap. /// A priority queue implemented with a binary heap.
/// ///
/// This can be either a min-heap or a max-heap. /// This can be either a min-heap or a max-heap.

View File

@ -1,6 +1,5 @@
use crate::{ use crate::{
sealed::binary_heap::Kind as BinaryHeapKind, BinaryHeap, IndexMap, IndexSet, LinearMap, String, binary_heap::Kind as BinaryHeapKind, BinaryHeap, IndexMap, IndexSet, LinearMap, String, Vec,
Vec,
}; };
use core::{fmt, marker::PhantomData}; use core::{fmt, marker::PhantomData};
use hash32::{BuildHasherDefault, Hash, Hasher}; use hash32::{BuildHasherDefault, Hash, Hasher};

View File

@ -21,36 +21,3 @@ where
defmt::write!(fmt, "{=str}", self.as_str()); defmt::write!(fmt, "{=str}", self.as_str());
} }
} }
#[cfg(test)]
mod tests {
use crate::Vec;
use defmt::Format;
#[test]
/// Tests encoding Vec with defmt, asserting these types may be serialized
/// Note: the exact wire format is NOT checked since its an unstable implementation detail of an external crate.
/// based on https://github.com/knurling-rs/defmt/blob/697a8e807bd766a80ada2d57514a9da1232dbc9a/tests/encode.rs#L523
fn test_defmt_format_vec() {
let val: Vec<_, 8> = Vec::from_slice(b"abc").unwrap();
let mut f = defmt::InternalFormatter::new();
let g = defmt::Formatter { inner: &mut f };
val.format(g);
f.finalize();
}
/// Tests encoding String with defmt, asserting these types may be serialized
/// Note: the exact wire format is NOT checked since its an unstable implementation detail of an external crate.
/// based loosely on https://github.com/knurling-rs/defmt/blob/main/tests/encode.rs#L483
#[test]
fn test_defmt_format_str() {
let mut val: crate::String<32> = crate::String::new();
val.push_str("foo").unwrap();
let mut f = defmt::InternalFormatter::new();
let g = defmt::Formatter { inner: &mut f };
val.format(g);
f.finalize();
}
}

View File

@ -368,6 +368,10 @@ pub struct IndexMap<K, V, S, const N: usize> {
impl<K, V, S, const N: usize> IndexMap<K, V, BuildHasherDefault<S>, N> { impl<K, V, S, const N: usize> IndexMap<K, V, BuildHasherDefault<S>, N> {
/// Creates an empty `IndexMap`. /// Creates an empty `IndexMap`.
pub const fn new() -> Self { pub const fn new() -> Self {
// Const assert
crate::sealed::greater_than_1::<N>();
crate::sealed::power_of_two::<N>();
IndexMap { IndexMap {
build_hasher: BuildHasherDefault::new(), build_hasher: BuildHasherDefault::new(),
core: CoreMap::new(), core: CoreMap::new(),

View File

@ -1,6 +1,6 @@
use crate::indexmap::{self, IndexMap}; use crate::indexmap::{self, IndexMap};
use core::{borrow::Borrow, fmt, iter::FromIterator}; use core::{borrow::Borrow, fmt, iter::FromIterator};
use hash32::{BuildHasher, BuildHasherDefault, FnvHasher, Hash, Hasher}; use hash32::{BuildHasher, BuildHasherDefault, FnvHasher, Hash};
/// A [`heapless::IndexSet`](./struct.IndexSet.html) using the /// A [`heapless::IndexSet`](./struct.IndexSet.html) using the
/// default FNV hasher. /// default FNV hasher.
@ -74,22 +74,13 @@ pub type FnvIndexSet<T, const N: usize> = IndexSet<T, BuildHasherDefault<FnvHash
/// println!("{}", book); /// println!("{}", book);
/// } /// }
/// ``` /// ```
pub struct IndexSet<T, S, const N: usize> pub struct IndexSet<T, S, const N: usize> {
where
T: Eq + Hash,
{
map: IndexMap<T, (), S, N>, map: IndexMap<T, (), S, N>,
} }
impl<T, S, const N: usize> IndexSet<T, BuildHasherDefault<S>, N> impl<T, S, const N: usize> IndexSet<T, BuildHasherDefault<S>, N> {
where
T: Eq + Hash,
S: Default + Hasher,
{
/// Creates an empty `IndexSet` /// Creates an empty `IndexSet`
pub fn new() -> Self { pub const fn new() -> Self {
assert!(N.is_power_of_two());
IndexSet { IndexSet {
map: IndexMap::new(), map: IndexMap::new(),
} }

View File

@ -1,57 +1,15 @@
/// Sealed traits and implementations for `binary_heap`
pub mod binary_heap {
use crate::binary_heap::{Max, Min};
use core::cmp::Ordering;
/// The binary heap kind: min-heap or max-heap
pub unsafe trait Kind {
#[doc(hidden)]
fn ordering() -> Ordering;
}
unsafe impl Kind for Min {
fn ordering() -> Ordering {
Ordering::Less
}
}
unsafe impl Kind for Max {
fn ordering() -> Ordering {
Ordering::Greater
}
}
}
/// Sealed traits and implementations for `LinkedList`
pub mod sorted_linked_list {
use crate::sorted_linked_list::{Max, Min};
use core::cmp::Ordering;
/// The linked list kind: min-list or max-list
pub unsafe trait Kind {
#[doc(hidden)]
fn ordering() -> Ordering;
}
unsafe impl Kind for Min {
fn ordering() -> Ordering {
Ordering::Less
}
}
unsafe impl Kind for Max {
fn ordering() -> Ordering {
Ordering::Greater
}
}
}
#[allow(dead_code)] #[allow(dead_code)]
#[allow(path_statements)] #[allow(path_statements)]
pub(crate) const fn smaller_than<const N: usize, const MAX: usize>() { pub(crate) const fn smaller_than<const N: usize, const MAX: usize>() {
Assert::<N, MAX>::LESS; Assert::<N, MAX>::LESS;
} }
#[allow(dead_code)]
#[allow(path_statements)]
pub(crate) const fn greater_than_eq_0<const N: usize>() {
Assert::<N, 0>::GREATER_EQ;
}
#[allow(dead_code)] #[allow(dead_code)]
#[allow(path_statements)] #[allow(path_statements)]
pub(crate) const fn greater_than_0<const N: usize>() { pub(crate) const fn greater_than_0<const N: usize>() {

View File

@ -1,6 +1,5 @@
use crate::{ use crate::{
sealed::binary_heap::Kind as BinaryHeapKind, BinaryHeap, IndexMap, IndexSet, LinearMap, String, binary_heap::Kind as BinaryHeapKind, BinaryHeap, IndexMap, IndexSet, LinearMap, String, Vec,
Vec,
}; };
use hash32::{BuildHasher, Hash}; use hash32::{BuildHasher, Hash};
use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer}; use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};

View File

@ -25,7 +25,7 @@
//! //!
//! [`BinaryHeap`]: `crate::binary_heap::BinaryHeap` //! [`BinaryHeap`]: `crate::binary_heap::BinaryHeap`
use crate::sealed::sorted_linked_list::Kind as LLKind; use core::cmp::Ordering;
use core::fmt; use core::fmt;
use core::marker::PhantomData; use core::marker::PhantomData;
use core::mem::MaybeUninit; use core::mem::MaybeUninit;
@ -50,6 +50,32 @@ pub struct Min;
/// Marker for Max sorted [`SortedLinkedList`]. /// Marker for Max sorted [`SortedLinkedList`].
pub struct Max; pub struct Max;
/// The linked list kind: min-list or max-list
pub trait Kind: private::Sealed {
#[doc(hidden)]
fn ordering() -> Ordering;
}
impl Kind for Min {
fn ordering() -> Ordering {
Ordering::Less
}
}
impl Kind for Max {
fn ordering() -> Ordering {
Ordering::Greater
}
}
/// Sealed traits
mod private {
pub trait Sealed {}
}
impl private::Sealed for Max {}
impl private::Sealed for Min {}
/// A node in the [`SortedLinkedList`]. /// A node in the [`SortedLinkedList`].
pub struct Node<T, Idx> { pub struct Node<T, Idx> {
val: MaybeUninit<T>, val: MaybeUninit<T>,
@ -57,14 +83,14 @@ pub struct Node<T, Idx> {
} }
/// The linked list. /// The linked list.
pub struct SortedLinkedList<T, Idx, Kind, const N: usize> pub struct SortedLinkedList<T, Idx, K, const N: usize>
where where
Idx: SortedLinkedListIndex, Idx: SortedLinkedListIndex,
{ {
list: [Node<T, Idx>; N], list: [Node<T, Idx>; N],
head: Idx, head: Idx,
free: Idx, free: Idx,
_kind: PhantomData<Kind>, _kind: PhantomData<K>,
} }
// Internal macro for generating indexes for the linkedlist and const new for the linked list // Internal macro for generating indexes for the linkedlist and const new for the linked list
@ -115,7 +141,7 @@ macro_rules! impl_index_and_const_new {
} }
} }
impl<T, Kind, const N: usize> SortedLinkedList<T, $name, Kind, N> { impl<T, K, const N: usize> SortedLinkedList<T, $name, K, N> {
const UNINIT: Node<T, $name> = Node { const UNINIT: Node<T, $name> = Node {
val: MaybeUninit::uninit(), val: MaybeUninit::uninit(),
next: $name::none(), next: $name::none(),
@ -156,7 +182,7 @@ impl_index_and_const_new!(LinkedIndexU8, u8, new_u8, 254); // val is 2^8 - 2 (on
impl_index_and_const_new!(LinkedIndexU16, u16, new_u16, 65_534); // val is 2^16 - 2 impl_index_and_const_new!(LinkedIndexU16, u16, new_u16, 65_534); // val is 2^16 - 2
impl_index_and_const_new!(LinkedIndexUsize, usize, new_usize, 4_294_967_294); // val is 2^32 - 2 impl_index_and_const_new!(LinkedIndexUsize, usize, new_usize, 4_294_967_294); // val is 2^32 - 2
impl<T, Idx, Kind, const N: usize> SortedLinkedList<T, Idx, Kind, N> impl<T, Idx, K, const N: usize> SortedLinkedList<T, Idx, K, N>
where where
Idx: SortedLinkedListIndex, Idx: SortedLinkedListIndex,
{ {
@ -205,11 +231,11 @@ where
} }
} }
impl<T, Idx, Kind, const N: usize> SortedLinkedList<T, Idx, Kind, N> impl<T, Idx, K, const N: usize> SortedLinkedList<T, Idx, K, N>
where where
T: Ord, T: Ord,
Idx: SortedLinkedListIndex, Idx: SortedLinkedListIndex,
Kind: LLKind, K: Kind,
{ {
/// Pushes a value onto the list without checking if the list is full. /// Pushes a value onto the list without checking if the list is full.
/// ///
@ -230,7 +256,7 @@ where
if self if self
.read_data_in_node_at(head) .read_data_in_node_at(head)
.cmp(self.read_data_in_node_at(new)) .cmp(self.read_data_in_node_at(new))
!= Kind::ordering() != K::ordering()
{ {
self.node_at_mut(new).next = self.head; self.node_at_mut(new).next = self.head;
self.head = Idx::new_unchecked(new); self.head = Idx::new_unchecked(new);
@ -242,7 +268,7 @@ where
if self if self
.read_data_in_node_at(next) .read_data_in_node_at(next)
.cmp(self.read_data_in_node_at(new)) .cmp(self.read_data_in_node_at(new))
!= Kind::ordering() != K::ordering()
{ {
break; break;
} }
@ -307,7 +333,7 @@ where
/// assert_eq!(iter.next(), Some(&1)); /// assert_eq!(iter.next(), Some(&1));
/// assert_eq!(iter.next(), None); /// assert_eq!(iter.next(), None);
/// ``` /// ```
pub fn iter(&self) -> Iter<'_, T, Idx, Kind, N> { pub fn iter(&self) -> Iter<'_, T, Idx, K, N> {
Iter { Iter {
list: self, list: self,
index: self.head, index: self.head,
@ -336,7 +362,7 @@ where
/// assert_eq!(ll.pop(), Ok(1)); /// assert_eq!(ll.pop(), Ok(1));
/// assert_eq!(ll.pop(), Err(())); /// assert_eq!(ll.pop(), Err(()));
/// ``` /// ```
pub fn find_mut<F>(&mut self, mut f: F) -> Option<FindMut<'_, T, Idx, Kind, N>> pub fn find_mut<F>(&mut self, mut f: F) -> Option<FindMut<'_, T, Idx, K, N>>
where where
F: FnMut(&T) -> bool, F: FnMut(&T) -> bool,
{ {
@ -486,21 +512,21 @@ where
} }
/// Iterator for the linked list. /// Iterator for the linked list.
pub struct Iter<'a, T, Idx, Kind, const N: usize> pub struct Iter<'a, T, Idx, K, const N: usize>
where where
T: Ord, T: Ord,
Idx: SortedLinkedListIndex, Idx: SortedLinkedListIndex,
Kind: LLKind, K: Kind,
{ {
list: &'a SortedLinkedList<T, Idx, Kind, N>, list: &'a SortedLinkedList<T, Idx, K, N>,
index: Idx, index: Idx,
} }
impl<'a, T, Idx, Kind, const N: usize> Iterator for Iter<'a, T, Idx, Kind, N> impl<'a, T, Idx, K, const N: usize> Iterator for Iter<'a, T, Idx, K, N>
where where
T: Ord, T: Ord,
Idx: SortedLinkedListIndex, Idx: SortedLinkedListIndex,
Kind: LLKind, K: Kind,
{ {
type Item = &'a T; type Item = &'a T;
@ -515,24 +541,24 @@ where
} }
/// Comes from [`SortedLinkedList::find_mut`]. /// Comes from [`SortedLinkedList::find_mut`].
pub struct FindMut<'a, T, Idx, Kind, const N: usize> pub struct FindMut<'a, T, Idx, K, const N: usize>
where where
T: Ord, T: Ord,
Idx: SortedLinkedListIndex, Idx: SortedLinkedListIndex,
Kind: LLKind, K: Kind,
{ {
list: &'a mut SortedLinkedList<T, Idx, Kind, N>, list: &'a mut SortedLinkedList<T, Idx, K, N>,
is_head: bool, is_head: bool,
prev_index: Idx, prev_index: Idx,
index: Idx, index: Idx,
maybe_changed: bool, maybe_changed: bool,
} }
impl<'a, T, Idx, Kind, const N: usize> FindMut<'a, T, Idx, Kind, N> impl<'a, T, Idx, K, const N: usize> FindMut<'a, T, Idx, K, N>
where where
T: Ord, T: Ord,
Idx: SortedLinkedListIndex, Idx: SortedLinkedListIndex,
Kind: LLKind, K: Kind,
{ {
fn pop_internal(&mut self) -> T { fn pop_internal(&mut self) -> T {
if self.is_head { if self.is_head {
@ -616,11 +642,11 @@ where
} }
} }
impl<T, Idx, Kind, const N: usize> Drop for FindMut<'_, T, Idx, Kind, N> impl<T, Idx, K, const N: usize> Drop for FindMut<'_, T, Idx, K, N>
where where
T: Ord, T: Ord,
Idx: SortedLinkedListIndex, Idx: SortedLinkedListIndex,
Kind: LLKind, K: Kind,
{ {
fn drop(&mut self) { fn drop(&mut self) {
// Only resort the list if the element has changed // Only resort the list if the element has changed
@ -631,11 +657,11 @@ where
} }
} }
impl<T, Idx, Kind, const N: usize> Deref for FindMut<'_, T, Idx, Kind, N> impl<T, Idx, K, const N: usize> Deref for FindMut<'_, T, Idx, K, N>
where where
T: Ord, T: Ord,
Idx: SortedLinkedListIndex, Idx: SortedLinkedListIndex,
Kind: LLKind, K: Kind,
{ {
type Target = T; type Target = T;
@ -645,11 +671,11 @@ where
} }
} }
impl<T, Idx, Kind, const N: usize> DerefMut for FindMut<'_, T, Idx, Kind, N> impl<T, Idx, K, const N: usize> DerefMut for FindMut<'_, T, Idx, K, N>
where where
T: Ord, T: Ord,
Idx: SortedLinkedListIndex, Idx: SortedLinkedListIndex,
Kind: LLKind, K: Kind,
{ {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
self.maybe_changed = true; self.maybe_changed = true;
@ -659,11 +685,11 @@ where
} }
// /// Useful for debug during development. // /// Useful for debug during development.
// impl<T, Idx, Kind, const N: usize> fmt::Debug for FindMut<'_, T, Idx, Kind, N> // impl<T, Idx, K, const N: usize> fmt::Debug for FindMut<'_, T, Idx, K, N>
// where // where
// T: Ord + core::fmt::Debug, // T: Ord + core::fmt::Debug,
// Idx: SortedLinkedListIndex, // Idx: SortedLinkedListIndex,
// Kind: LLKind, // K: Kind,
// { // {
// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// f.debug_struct("FindMut") // f.debug_struct("FindMut")
@ -683,18 +709,18 @@ where
// } // }
// } // }
impl<T, Idx, Kind, const N: usize> fmt::Debug for SortedLinkedList<T, Idx, Kind, N> impl<T, Idx, K, const N: usize> fmt::Debug for SortedLinkedList<T, Idx, K, N>
where where
T: Ord + core::fmt::Debug, T: Ord + core::fmt::Debug,
Idx: SortedLinkedListIndex, Idx: SortedLinkedListIndex,
Kind: LLKind, K: Kind,
{ {
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()
} }
} }
impl<T, Idx, Kind, const N: usize> Drop for SortedLinkedList<T, Idx, Kind, N> impl<T, Idx, K, const N: usize> Drop for SortedLinkedList<T, Idx, K, N>
where where
Idx: SortedLinkedListIndex, Idx: SortedLinkedListIndex,
{ {

View File

@ -1,4 +1,7 @@
use core::{cmp::Ordering, fmt, hash, iter::FromIterator, mem::MaybeUninit, ops, ptr, slice}; use core::{
cmp::Ordering, convert::TryFrom, fmt, hash, iter::FromIterator, mem::MaybeUninit, ops, ptr,
slice,
};
use hash32; use hash32;
/// 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)
@ -53,8 +56,8 @@ impl<T, const N: usize> Vec<T, N> {
/// ``` /// ```
/// `Vec` `const` constructor; wrap the returned value in [`Vec`](../struct.Vec.html) /// `Vec` `const` constructor; wrap the returned value in [`Vec`](../struct.Vec.html)
pub const fn new() -> Self { pub const fn new() -> Self {
// Const assert N > 0 // Const assert N >= 0
crate::sealed::greater_than_0::<N>(); crate::sealed::greater_than_eq_0::<N>();
Self { Self {
buffer: [Self::INIT; N], buffer: [Self::INIT; N],
@ -569,6 +572,14 @@ impl<T, const N: usize> Drop for Vec<T, N> {
} }
} }
impl<'a, T: Clone, const N: usize> TryFrom<&'a [T]> for Vec<T, N> {
type Error = ();
fn try_from(slice: &'a [T]) -> Result<Self, Self::Error> {
Vec::from_slice(slice)
}
}
impl<T, const N: usize> Extend<T> for Vec<T, N> { impl<T, const N: usize> Extend<T> for Vec<T, N> {
fn extend<I>(&mut self, iter: I) fn extend<I>(&mut self, iter: I)
where where
@ -1222,4 +1233,29 @@ mod tests {
assert!(!v.ends_with(b"ba")); assert!(!v.ends_with(b"ba"));
assert!(!v.ends_with(b"a")); assert!(!v.ends_with(b"a"));
} }
#[test]
fn zero_capacity() {
let mut v: Vec<u8, 0> = Vec::new();
// Validate capacity
assert_eq!(v.capacity(), 0);
// Make sure there is no capacity
assert!(v.push(1).is_err());
// Validate length
assert_eq!(v.len(), 0);
// Validate pop
assert_eq!(v.pop(), None);
// Validate slice
assert_eq!(v.as_slice(), &[]);
// Validate empty
assert!(v.is_empty());
// Validate full
assert!(v.is_full());
}
} }