/// Gets the [`ConstVal::VAL`](trait.ConstVal.html#associatedconstant.VAL)
/// associated constant for a type.
///
/// Use this macro to unambiguously use the [`ConstVal::VAL`] associated constant,
/// as opposed to an inherent `VAL` associated constant,
/// or a `VAL` associated constant from another trait.
///
/// # Examples
///
/// ### Quasiconstants
///
/// Using the [`quasiconst`] macro to declare (generic) constants.
///
#[cfg_attr(not(feature = "integers"), doc = " ```ignore")]
#[cfg_attr(feature = "integers", doc = " ```rust")]
/// use core_extensions::{getconst, quasiconst, IntegerExt};
///
/// #[derive(Debug, PartialEq)]
/// pub struct Single(pub T);
///
/// quasiconst!{const Foo: &'static str = "hello"}
/// quasiconst!{const Bar: &'static str = "world"}
/// quasiconst!{const SINGLE_INT[T: IntegerExt = u8]: Single = Single(T::ONE) }
///
/// assert_eq!(getconst!(Foo), "hello");
/// assert_eq!(getconst!(Bar), "world");
///
/// // `SINGLE_INT` == `SINGLE_INT`, because of the defaulted type parameter
/// assert_eq!(getconst!(SINGLE_INT), Single(1_u8));
///
/// assert_eq!(getconst!(SINGLE_INT), Single(1_u16));
///
/// assert_eq!(getconst!(SINGLE_INT<_>), Single(1_i8));
///
/// // `Type<..>` is special syntax from `getconst`, to infer all generic parameters.
/// assert_eq!(getconst!(SINGLE_INT<..>), Single(1u128));
///
/// ```
///
/// ### Inherent `VAL` associated constant
///
/// This demonstrates how inherent associated constants have priority over
/// trait associated constants.
///
/// ```rust
/// use core_extensions::{ConstVal, getconst};
///
/// #[derive(Debug, PartialEq)]
/// struct Foo(u32);
///
/// impl ConstVal for Foo {
/// type Ty = &'static str;
/// const VAL: Self::Ty = "hello";
/// }
///
/// impl Foo {
/// const VAL: &'static str = "world";
/// }
///
/// assert_eq!(getconst!(Foo), "hello");
/// assert_eq!(::VAL, "hello");
/// assert_eq!(Foo::VAL, "world");
///
/// ```
///
/// [`ConstVal::VAL`]: trait.ConstVal.html#associatedconstant.VAL
/// [`quasiconst`]: ./macro.quasiconst.html
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "const_val")))]
#[macro_export]
macro_rules! getconst {
(
$(:: $(@$leading:tt@)? )? $($path:ident)::* <..>
) => ({
use $crate::ConstVal;
$(:: $(@$leading@)? )? $($path)::* ::__CORE_EXTENSIONS__05FFE5XDEJHD07CTUSQMW
});
($ty:ty) => {<$ty as $crate::ConstVal>::VAL};
}
/// Declare types that emulate generic constants.
///
/// # Syntax
///
/// For an example using all the syntax, you can look at the
/// [All of the syntax section](#allthesyntax)
///
/// # 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
///
/// ```rust
/// use core_extensions::{getconst, quasiconst};
///
/// quasiconst!{ const NONE: Option = None }
///
/// // `getconst` is the unambiguous way to get the constant
/// assert_eq!([getconst!(NONE); 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::::VAL; 4], [None, None, None, None]);
///
/// ```
///
/// ### `ConstVal`
///
/// This example shows that you can use the generic constants with the [`ConstVal`] trait
///
#[cfg_attr(not(all(feature = "const_default", feature = "alloc")), doc = " ```ignore")]
#[cfg_attr(all(feature = "const_default", feature = "alloc"), doc = " ```rust")]
/// use core_extensions::{ConstDefault, ConstVal, quasiconst};
///
/// quasiconst!{
/// pub const PAIR: (T, T) = ConstDefault::DEFAULT;
/// }
///
/// fn constant() -> U::Ty {
/// U::VAL
/// }
///
/// /// You can pass the type you want `constrained` to return as the first type argument.
/// fn constrained>() -> T {
/// U::VAL
/// }
///
/// assert_eq!(constant::>(), ([0, 0, 0], [0, 0, 0]));
/// assert_eq!(constant::>(), (false, false));
///
/// // Pair<_> is inferred to be `Pair`
/// assert_eq!(constrained::<(u8, u8), PAIR<_>>(), (0, 0));
///
/// // Pair<_> is inferred to be `Pair`
/// 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).
///
#[cfg_attr(not(all(feature = "const_default", feature = "rust_1_51")), doc = " ```ignore")]
#[cfg_attr(all(feature = "const_default", feature = "rust_1_51"), doc = " ```rust")]
/// 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: [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.
///
#[cfg_attr(not(all(feature = "const_default", feature = "rust_1_51")), doc = " ```ignore")]
#[cfg_attr(all(feature = "const_default", feature = "rust_1_51"), doc = " ```rust")]
/// 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
/// };
/// }
///
/// ```
///
/// [`ConstVal`]: ./trait.ConstVal.html
///
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "const_val")))]
#[macro_export]
macro_rules! quasiconst {
(
$(#[$attr:meta])*
$vis:vis const $ident:ident
$( [$($generic_params:tt)*] )?
: $ty: ty
$(where [$($constraints:tt)*] )?
= $value:expr
$(; $($rem:tt)* )?
) => {
$crate::parse_generics!{
$crate::__declare_const_inner!{
(
$(#[$attr])*,
$vis,
$ident,
$ty,
[$($($constraints)*)?],
$value,
concat!("Cosntructs a `", stringify!($ident), "` (the type)"),
)
}
($($($generic_params)*)?)
}
$($crate::quasiconst!{ $($rem)* })?
};
(
$(#[$attr:meta])*
$vis:vis const $ident:ident
$($rem:tt)*
) => {
$crate::parse_generics_and_where!{
$crate::__declare_const_angle_inner!{
(
$(#[$attr])*,
$vis,
$ident,
concat!("Cosntructs a `", stringify!($ident), "` (the type)"),
)
}
($($rem)*)
}
};
($(;)?)=>{};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __declare_const_inner {
(
(
$(#[$attr:meta])*,
$vis:vis,
$ident:ident,
$ty: ty,
[$($constraints:tt)*],
$value:expr,
$new_doc:expr,
)
($($struct_params:tt)*)
($($impl_params:tt)*)
($($impl_args:tt)*)
($($phantoms:tt)*)
) => {
$(#[$attr])*
#[allow(non_camel_case_types)]
$vis struct $ident <$($struct_params)*> {
_marker: $($phantoms)*
}
impl<$($impl_params)*> $crate::ConstVal for $ident<$($impl_args)*>
where
$($constraints)*
{
type Ty = $ty;
const VAL: ::Ty = $value;
}
impl<$($impl_params)*> $ident<$($impl_args)*>
where
$($constraints)*
{
#[doc = $new_doc]
$vis const NEW: Self = Self{_marker: $crate::__::PD};
/// The constant that this type represents.
$vis const VAL: ::Ty = ::VAL;
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! __declare_const_angle_inner {
(
(
$(#[$attr:meta])*,
$vis:vis,
$ident:ident,
$new_doc:expr,
)
$struct_params:tt
$impl_params:tt
$impl_args:tt
$phantoms:tt
(: $ty: ty)
($($where:tt)*)
(= $value:expr $(; $($($more:tt)+)? )? )
) => {
$crate::__declare_const_inner!{
(
$(#[$attr])*,
$vis,
$ident,
$ty,
[$($where)*],
$value,
$new_doc,
)
$struct_params
$impl_params
$impl_args
$phantoms
}
$($(
$crate::quasiconst!{
$($more)*
}
)?)?
}
}