macro_rules! quasiconst {
    (
        $(#[$attr:meta])*
        $vis:vis const $ident:ident
        $( [$($generic_params:tt)*] )? 
        : $ty: ty
        $(where [$($constraints:tt)*] )?
        = $value:expr
        $(; $($rem:tt)* )?
    ) => { ... };
    (
        $(#[$attr:meta])*
        $vis:vis const $ident:ident
        $($rem:tt)*
    ) => { ... };
    ($(;)?) => { ... };
}
Available on crate feature const_val only.
Expand description

Declare types that emulate generic constants.

Syntax

For an example using all the syntax, you can look at the All of the syntax section

Generated code

This macro generates:

  • A generic zero-sized struct with the name and generic parameters of the const definition passed to this macro.

  • An impl of the ConstVal trait for the struct, with the value for the constant .

  • An inherent VAL associated constant for the struct, to avoid requiring that ConstVal is imported to write Foo::VAL.

  • An inherent NEW associated constant that constructs the struct.

Examples

Basic

use core_extensions::{getconst, quasiconst};
 
quasiconst!{ const NONE<T>: Option<T> = None }
 
// `getconst` is the unambiguous way to get the constant
assert_eq!([getconst!(NONE<String>); 4], [None, None, None, None]);

// The `VAL` associated constant is another way to get the constant.
//
// I get worse compiler errors with `::VAL` than with `getconst`
// when the bounds of the generic constant aren't satisfied.
assert_eq!([NONE::<u8>::VAL; 4], [None, None, None, None]);
 

ConstVal

This example shows that you can use the generic constants with the ConstVal trait

use core_extensions::{ConstDefault, ConstVal, quasiconst};

quasiconst!{
   pub const PAIR<T: ConstDefault>: (T, T) = ConstDefault::DEFAULT;
}

fn constant<U: ConstVal>() -> U::Ty {
   U::VAL
}

/// You can pass the type you want `constrained` to return as the first type argument.
fn constrained<T, U: ConstVal<Ty = T>>() -> T {
   U::VAL
}

assert_eq!(constant::<PAIR<[u8; 3]>>(), ([0, 0, 0], [0, 0, 0]));
assert_eq!(constant::<PAIR<bool>>(), (false, false));

// Pair<_> is inferred to be `Pair<u8>`
assert_eq!(constrained::<(u8, u8), PAIR<_>>(), (0, 0));

// Pair<_> is inferred to be `Pair<String>`
assert_eq!(constrained::<(String, String), PAIR<_>>(), (String::new(), String::new()));

Newer syntax

This is the newer syntax that looks closest to what generic constants would look like.

Note: This macro allows const parameters (and doesn’t require enabling the “rust_1_51” feature to use them).

use core_extensions::{ConstDefault, getconst, quasiconst};

assert_eq!(getconst!(REFD<'static>), "");
assert_eq!(getconst!(REFD<'static, str>), "");
assert_eq!(getconst!(REFD<'static, [u8]>), &[]);

assert_eq!(getconst!(CONST_GEN<2>), [1, 3]);
assert_eq!(getconst!(CONST_GEN<4>), [1, 3, 6, 10]);
assert_eq!(getconst!(CONST_GEN<6>), [1, 3, 6, 10, 15, 21]);

quasiconst!{
   /// You can document and use attributes on the generated `REFD` struct.
   pub(crate) const REFD<'a: 'a, T: 'a + ?Sized = str>: &'a T
   where
       &'a T: ConstDefault
   = <&'a T>::DEFAULT;
}
quasiconst!{
   // Defaulted const parameters require Rust 1.59.0
   pub const CONST_GEN<const N: usize>: [u128; N] = {
       let mut array = [1u128; N];
       let mut i = 1;
       while i < array.len() {
           array[i] += array[i - 1] + i as u128;
           i += 1;
       }
       array
   };
}

Older syntax

This is the older (but equally supported) syntax for generic parameters and where clauses, using [] for both of them.

use core_extensions::{ConstDefault, getconst, quasiconst};

assert_eq!(getconst!(REFD<'static>), "");
assert_eq!(getconst!(REFD<'static, str>), "");
assert_eq!(getconst!(REFD<'static, [u8]>), &[]);

assert_eq!(getconst!(CONST_GEN<2>), [1, 3]);
assert_eq!(getconst!(CONST_GEN<4>), [1, 3, 6, 10]);
assert_eq!(getconst!(CONST_GEN<6>), [1, 3, 6, 10, 15, 21]);

quasiconst!{
   /// You can document and use attributes on the generated `REFD` struct.
   pub(crate) const REFD['a: 'a, T: 'a + ?Sized = str]: &'a T
   where[&'a T: ConstDefault]
   = <&'a T>::DEFAULT;
    
   // The macro parses defaulted const parameters, but they're not supported by Rust yet.
   pub const CONST_GEN[const N: usize]: [u128; N] = {
       let mut array = [1u128; N];
       let mut i = 1;
       while i < array.len() {
           array[i] += array[i - 1] + i as u128;
           i += 1;
       }
       array
   };
}