#![doc = include_str!("../README.md")]
#![deny(missing_docs)]
#[macro_export]
macro_rules! const_map {
($name:ident, $lookup:ident(), ($kty:ty => $vty:ty) { $($k:expr => $v:expr),* $(,)? }) => {
pub const $name: [($kty, $vty); $crate::count!($(($k, $v))*)] = [$(($k, $v)),*];
const fn $lookup(key: $kty) -> Option<$vty> {
#[inline]
const fn find(pairs: &[($kty, $vty)], key: $kty, n: usize) -> Option<$vty> {
if n >= pairs.len() {
return None;
}
match pairs[n] {
(k, v) if k == key => Some(v),
_ => find(pairs, key, n + 1),
}
}
find(&Self::$name, key, 0)
}
};
}
#[doc(hidden)]
#[macro_export]
macro_rules! count {
() => (0usize);
($x:tt $($xs:tt)*) => (1usize + $crate::count!($($xs)*));
}
#[cfg(test)]
mod test {
struct S1;
impl S1 {
const_map!(MAP, map_get(), (char => &'static str) {
'a' => "apple",
'b' => "banana",
'c' => "clementine",
'd' => "durian",
});
}
pub struct S2<const TAG: char>;
impl<const TAG: char> S2<TAG> {
pub const FRUIT: &'static str = match S1::map_get(TAG) {
Some(s) => s,
None => panic!("no fruit found"),
};
}
#[test]
fn test() {
assert_eq!(S1::map_get('b'), Some("banana"));
assert_eq!(S1::map_get('x'), None);
}
#[test]
fn test_generic_const() {
assert_eq!(S2::<'d'>::FRUIT, "durian");
}
}
#[cfg(doctest)]
fn test_generic_const_panic() {}