Skip to content

Commit

Permalink
Trait for default const values
Browse files Browse the repository at this point in the history
Introduces a trait defining an associated constant of the `Self` type.
An implementation is provided for `GenericArray`, providing means of
constructing default `GenericArray`s in const context.

This plugs a gap that exists even if fizyk20#130 is merged, as generic type
parameters cannot currently be referenced in const context (e.g. if the
repetition length provided to the `arr!` macro comes from a type
parameter).
  • Loading branch information
eggyal committed Sep 11, 2022
1 parent d011b97 commit 7a650d9
Showing 1 changed file with 117 additions and 0 deletions.
117 changes: 117 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ mod impl_serde;
#[cfg(feature = "zeroize")]
mod impl_zeroize;

use core::cell::{Cell, RefCell, UnsafeCell};
use core::iter::FromIterator;
use core::marker::PhantomData;
use core::mem::{MaybeUninit, ManuallyDrop};
Expand Down Expand Up @@ -118,6 +119,100 @@ unsafe impl<T> ArrayLength<T> for UTerm {
type ArrayType = [T; 0];
}

/// Trait providing access to a constant value of the `Self` type.
///
/// The following implementations are provided:
/// * for numerics (integers and floats), value of zero
/// * for [`bool`], value of `false`
/// * for [`char`], value of the null-character `'\0'`
/// * for slices (including of [`str`]), value of the empty slice `&[]` (or empty string `""`)
/// * for raw pointers, a null pointer
/// * for tuples of up to 10 elements and arrays of any length (where element type implements
/// `ConstDefault`), the tuple/array of `DEFAULT`s
///
/// ```rust
/// # use generic_array::{
/// # ConstDefault,
/// # GenericArray,
/// # typenum::U5,
/// # };
/// use std::f32::consts::PI;
///
/// #[derive(Debug, PartialEq)]
/// struct Food(f32);
///
/// impl ConstDefault for Food {
/// const DEFAULT: Self = Self(PI);
/// }
///
/// const BUFFET: GenericArray<Food, U5> = GenericArray::DEFAULT;
/// assert_eq!(BUFFET[3], Food(PI));
/// ```
pub trait ConstDefault: Sized {
/// The constant value of the `Self` type distinguished by the type parameter `X`
const DEFAULT: Self;
}

macro_rules! const_value {
() => {};
(tuple: $($param:ident),*;) => {
impl<$($param: ConstDefault),*> ConstDefault for ($($param,)*) {
const DEFAULT: Self = ($($param::DEFAULT,)*);
}
};
(tuples:; $($rest:tt)*) => {
const_value!(tuple:;);
const_value!($($rest)*);
};
(tuples: $head:ident $(,$tail:ident)*; $($rest:tt)*) => {
const_value!(tuple: $head $(,$tail)*;);
const_value!(tuples: $($tail),*; $($rest)*);
};
($v:expr => $($t:ty),+; $($rest:tt)*) => {
$(impl ConstDefault for $t {
const DEFAULT: Self = $v;
})+
const_value!($($rest)*);
};
}

const_value! {
0 => i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, isize, usize;
0. => f32, f64;
false => bool;
'\0' => char;
"" => &str;
tuples: A, B, C, D, E, F, G, H, I, J;
}

impl<T: 'static> ConstDefault for &[T] {
const DEFAULT: Self = &[];
}

impl<T: ConstDefault, const N: usize> ConstDefault for [T; N] {
const DEFAULT: Self = [T::DEFAULT; N];
}

impl<T> ConstDefault for *const T {
const DEFAULT: Self = core::ptr::null();
}

impl<T> ConstDefault for *mut T {
const DEFAULT: Self = core::ptr::null_mut();
}

impl<T: ConstDefault> ConstDefault for Cell<T> {
const DEFAULT: Self = Self::new(T::DEFAULT);
}

impl<T: ConstDefault> ConstDefault for RefCell<T> {
const DEFAULT: Self = Self::new(T::DEFAULT);
}

impl<T: ConstDefault> ConstDefault for UnsafeCell<T> {
const DEFAULT: Self = Self::new(T::DEFAULT);
}

/// Internal type used to generate a struct of appropriate size
#[allow(dead_code)]
#[repr(C)]
Expand All @@ -128,6 +223,14 @@ pub struct GenericArrayImplEven<T, U> {
_marker: PhantomData<T>,
}

impl<T, U: ConstDefault> ConstDefault for GenericArrayImplEven<T, U> {
const DEFAULT: Self = Self {
parent1: U::DEFAULT,
parent2: U::DEFAULT,
_marker: PhantomData,
};
}

impl<T: Clone, U: Clone> Clone for GenericArrayImplEven<T, U> {
fn clone(&self) -> GenericArrayImplEven<T, U> {
GenericArrayImplEven {
Expand All @@ -150,6 +253,14 @@ pub struct GenericArrayImplOdd<T, U> {
data: T,
}

impl<T: ConstDefault, U: ConstDefault> ConstDefault for GenericArrayImplOdd<T, U> {
const DEFAULT: Self = Self {
parent1: U::DEFAULT,
parent2: U::DEFAULT,
data: T::DEFAULT,
};
}

impl<T: Clone, U: Clone> Clone for GenericArrayImplOdd<T, U> {
fn clone(&self) -> GenericArrayImplOdd<T, U> {
GenericArrayImplOdd {
Expand Down Expand Up @@ -179,6 +290,12 @@ pub struct GenericArray<T, U: ArrayLength<T>> {
data: U::ArrayType,
}

impl<T, U: ArrayLength<T>> ConstDefault for GenericArray<T, U>
where U::ArrayType: ConstDefault,
{
const DEFAULT: Self = Self { data: ConstDefault::DEFAULT };
}

unsafe impl<T: Send, N: ArrayLength<T>> Send for GenericArray<T, N> {}
unsafe impl<T: Sync, N: ArrayLength<T>> Sync for GenericArray<T, N> {}

Expand Down

0 comments on commit 7a650d9

Please # to comment.