Replace A: Default bounds by a constructor on Array (#112)

* Add Array::default function to construct a default array

* Use Array::default instead of Default::default to allow supporting all array sizes

* Missed impl Array for [T; 33] 🍀

* Avoid needing `[T; N]: Default with const-generics
This commit is contained in:
Nemo157 2020-08-17 18:55:51 +02:00 committed by GitHub
parent 46554393bf
commit d3c1c6a56d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 2521 additions and 84 deletions

53
gen-array-impls.sh Executable file
View File

@ -0,0 +1,53 @@
#!/usr/bin/env bash
gen_impl() {
local len=$1
cat <<-END
impl<T: Default> Array for [T; $len] {
type Item = T;
const CAPACITY: usize = $len;
#[inline(always)]
#[must_use]
fn as_slice(&self) -> &[T] {
&*self
}
#[inline(always)]
#[must_use]
fn as_slice_mut(&mut self) -> &mut [T] {
&mut *self
}
#[inline(always)]
fn default() -> Self {
[
$(for ((i = 0; i < $len; i += 6))
do
echo -n ' '
for ((j = 0; j < 6 && j + i < $len; j++))
do
echo -n ' T::default(),'
done
echo
done)
]
}
}
END
}
cat <<-END
// Generated file, to regenerate run
// ./gen-array-impls.sh > src/array/generated_impl.rs
// from the repo root
use super::Array;
$(for ((i = 0; i <= 33; i++)); do gen_impl $i; done)
$(for ((i = 64; i <= 4096; i *= 2)); do gen_impl $i; done)
END
# vim: noet

View File

@ -34,49 +34,14 @@ pub trait Array {
/// A correct implementation will return a slice with a length equal to the
/// `CAPACITY` value.
fn as_slice_mut(&mut self) -> &mut [Self::Item];
/// Create a default-initialized instance of ourself, similar to the [`Default`] trait, but
/// implemented for the same range of sizes as [`Array`].
fn default() -> Self;
}
#[cfg(feature = "nightly_const_generics")]
impl<T: Default, const N: usize> Array for [T; N] {
type Item = T;
const CAPACITY: usize = N;
#[inline(always)]
#[must_use]
fn as_slice(&self) -> &[T] {
&*self
}
#[inline(always)]
#[must_use]
fn as_slice_mut(&mut self) -> &mut [T] {
&mut *self
}
}
mod const_generic_impl;
#[cfg(not(feature = "nightly_const_generics"))]
macro_rules! impl_array_for_len {
($($len:expr),+ $(,)?) => {
$(impl<T: Default> Array for [T; $len] {
type Item = T;
const CAPACITY: usize = $len;
#[inline(always)]
#[must_use]
fn as_slice(&self) -> &[T] {
&*self
}
#[inline(always)]
#[must_use]
fn as_slice_mut(&mut self) -> &mut [T] {
&mut *self
}
})+
}
}
#[cfg(not(feature = "nightly_const_generics"))]
impl_array_for_len! {
0, /* The oft-forgotten 0-length array! */
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
33, /* for luck */
64, 128, 256, 512, 1024, 2048, 4096,
}
mod generated_impl;

View File

@ -0,0 +1,23 @@
use super::Array;
impl<T: Default, const N: usize> Array for [T; N] {
type Item = T;
const CAPACITY: usize = N;
#[inline(always)]
#[must_use]
fn as_slice(&self) -> &[T] {
&*self
}
#[inline(always)]
#[must_use]
fn as_slice_mut(&mut self) -> &mut [T] {
&mut *self
}
#[inline(always)]
fn default() -> Self {
[(); N].map(|_| Default::default())
}
}

2415
src/array/generated_impl.rs Normal file

File diff suppressed because it is too large Load Diff

View File

@ -15,9 +15,6 @@ use serde::ser::{Serialize, SerializeSeq, Serializer};
/// You specify the backing array type, and optionally give all the elements you
/// want to initially place into the array.
///
/// As an unfortunate restriction, the backing array type must support `Default`
/// for it to work with this macro.
///
/// ```rust
/// use tinyvec::*;
///
@ -64,8 +61,7 @@ macro_rules! array_vec {
///
/// ## Construction
///
/// If the backing array supports Default (length 32 or less), then you can use
/// the `array_vec!` macro similarly to how you might use the `vec!` macro.
/// You can use the `array_vec!` macro similarly to how you might use the `vec!` macro.
/// Specify the array type, then optionally give all the initial values you want
/// to have.
/// ```rust
@ -99,12 +95,21 @@ macro_rules! array_vec {
/// assert_eq!(more_ints.len(), 2);
/// ```
#[repr(C)]
#[derive(Clone, Copy, Default)]
#[derive(Clone, Copy)]
pub struct ArrayVec<A: Array> {
len: u16,
pub(crate) data: A,
}
impl<A: Array> Default for ArrayVec<A> {
fn default() -> Self {
Self {
len: 0,
data: A::default(),
}
}
}
impl<A: Array> Deref for ArrayVec<A> {
type Target = [A::Item];
#[inline(always)]
@ -160,7 +165,6 @@ where
#[cfg(feature = "serde")]
impl<'de, A: Array> Deserialize<'de> for ArrayVec<A>
where
A: Default,
A::Item: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
@ -470,10 +474,7 @@ impl<A: Array> ArrayVec<A> {
/// Makes a new, empty `ArrayVec`.
#[inline(always)]
#[must_use]
pub fn new() -> Self
where
A: Default,
{
pub fn new() -> Self {
Self::default()
}
@ -733,10 +734,7 @@ impl<A: Array> ArrayVec<A> {
/// assert_eq!(&av2[..], [2, 3]);
/// ```
#[inline]
pub fn split_off(&mut self, at: usize) -> Self
where
Self: Default,
{
pub fn split_off(&mut self, at: usize) -> Self {
// FIXME: should this just use drain into the output?
if at > self.len() {
panic!(
@ -1133,7 +1131,7 @@ impl<A: Array> From<A> for ArrayVec<A> {
}
}
impl<A: Array + Default> FromIterator<A::Item> for ArrayVec<A> {
impl<A: Array> FromIterator<A::Item> for ArrayVec<A> {
#[inline]
#[must_use]
fn from_iter<T: IntoIterator<Item = A::Item>>(iter: T) -> Self {
@ -1550,7 +1548,6 @@ struct ArrayVecVisitor<A: Array>(PhantomData<A>);
#[cfg(feature = "serde")]
impl<'de, A: Array> Visitor<'de> for ArrayVecVisitor<A>
where
A: Default,
A::Item: Deserialize<'de>,
{
type Value = ArrayVec<A>;

View File

@ -4,7 +4,7 @@
feature = "nightly_slice_partition_dedup",
feature(slice_partition_dedup)
)]
#![cfg_attr(feature = "nightly_const_generics", feature(min_const_generics))]
#![cfg_attr(feature = "nightly_const_generics", feature(min_const_generics, array_map))]
#![cfg_attr(docs_rs, feature(doc_cfg))]
#![warn(clippy::missing_inline_in_public_items)]
#![warn(clippy::must_use_candidate)]

View File

@ -17,9 +17,6 @@ use serde::ser::{Serialize, SerializeSeq, Serializer};
/// You specify the backing array type, and optionally give all the elements you
/// want to initially place into the array.
///
/// As an unfortunate restriction, the backing array type must support `Default`
/// for it to work with this macro.
///
/// ```rust
/// use tinyvec::*;
///
@ -98,7 +95,8 @@ pub enum TinyVec<A: Array> {
#[allow(missing_docs)]
Heap(Vec<A::Item>),
}
impl<A: Array + Default> Default for TinyVec<A> {
impl<A: Array> Default for TinyVec<A> {
#[inline]
#[must_use]
fn default() -> Self {
@ -164,7 +162,6 @@ where
#[cfg(feature = "serde")]
impl<'de, A: Array> Deserialize<'de> for TinyVec<A>
where
A: Default,
A::Item: Deserialize<'de>,
{
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
@ -203,10 +200,7 @@ impl<A: Array> TinyVec<A> {
/// tv.shrink_to_fit();
/// assert!(tv.is_inline());
/// ```
pub fn shrink_to_fit(&mut self)
where
A: Default,
{
pub fn shrink_to_fit(&mut self) {
let vec = match self {
TinyVec::Inline(_) => return,
TinyVec::Heap(h) => h,
@ -336,10 +330,7 @@ impl<A: Array> TinyVec<A> {
/// ```
#[inline]
#[must_use]
pub fn with_capacity(cap: usize) -> Self
where
A: Default,
{
pub fn with_capacity(cap: usize) -> Self {
if cap <= A::CAPACITY {
TinyVec::Inline(ArrayVec::default())
} else {
@ -668,10 +659,7 @@ impl<A: Array> TinyVec<A> {
/// Makes a new, empty vec.
#[inline(always)]
#[must_use]
pub fn new() -> Self
where
A: Default,
{
pub fn new() -> Self {
Self::default()
}
@ -778,10 +766,7 @@ impl<A: Array> TinyVec<A> {
/// assert_eq!(tv2.as_slice(), &[2, 3][..]);
/// ```
#[inline]
pub fn split_off(&mut self, at: usize) -> Self
where
A: Default,
{
pub fn split_off(&mut self, at: usize) -> Self {
match self {
TinyVec::Inline(a) => TinyVec::Inline(a.split_off(at)),
TinyVec::Heap(v) => TinyVec::Heap(v.split_off(at)),
@ -1104,7 +1089,7 @@ impl<A: Array> From<A> for TinyVec<A> {
impl<T, A> From<&'_ [T]> for TinyVec<A>
where
T: Clone + Default,
A: Array<Item = T> + Default,
A: Array<Item = T>,
{
#[inline]
#[must_use]
@ -1123,7 +1108,7 @@ where
impl<T, A> From<&'_ mut [T]> for TinyVec<A>
where
T: Clone + Default,
A: Array<Item = T> + Default,
A: Array<Item = T>,
{
#[inline]
#[must_use]
@ -1132,7 +1117,7 @@ where
}
}
impl<A: Array + Default> FromIterator<A::Item> for TinyVec<A> {
impl<A: Array> FromIterator<A::Item> for TinyVec<A> {
#[inline]
#[must_use]
fn from_iter<T: IntoIterator<Item = A::Item>>(iter: T) -> Self {
@ -1457,7 +1442,6 @@ struct TinyVecVisitor<A: Array>(PhantomData<A>);
#[cfg(feature = "serde")]
impl<'de, A: Array> Visitor<'de> for TinyVecVisitor<A>
where
A: Default,
A::Item: Deserialize<'de>,
{
type Value = TinyVec<A>;