use nutype::nutype;
#[nutype(
const_fn,
validate(greater_or_equal = 1, less_or_equal = 2_147_483_647),
derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Display, TryFrom, Into, FromStr)
)]
pub struct ApiLevel(u32);
macro_rules! api_levels {
($($name:ident = $level:literal,)+) => {
impl ApiLevel {
$(pub const $name: Self = match Self::try_new($level) {
Ok(level) => level,
Err(_) => panic!("invalid API level constant"),
};)+
}
};
}
api_levels! {
BASE = 1,
GINGERBREAD = 9,
JELLY_BEAN_MR2 = 18,
KITKAT = 19,
LOLLIPOP = 21,
M = 23,
N = 24,
O = 26,
P = 28,
Q = 29,
R = 30,
S = 31,
TIRAMISU = 33,
UPSIDE_DOWN_CAKE = 34,
VANILLA_ICE_CREAM = 35,
BAKLAVA = 36,
}
impl ApiLevel {
pub const fn get(self) -> u32 {
self.into_inner()
}
}
#[nutype(
const_fn,
validate(greater_or_equal = 1, less_or_equal = 2_100_000_000),
derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Display, TryFrom, Into, FromStr)
)]
pub struct VersionCode(u32);
impl VersionCode {
pub const ONE: Self = match Self::try_new(1) {
Ok(code) => code,
Err(_) => panic!("invalid version code constant"),
};
pub const fn get(self) -> u32 {
self.into_inner()
}
}
impl Default for VersionCode {
fn default() -> Self {
Self::ONE
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn bounds() {
assert!(matches!(ApiLevel::try_new(0), Err(ApiLevelError::GreaterOrEqualViolated)));
assert!(matches!(ApiLevel::try_new(i32::MAX as u32 + 1), Err(ApiLevelError::LessOrEqualViolated)));
assert_eq!(ApiLevel::try_new(24).unwrap(), ApiLevel::N);
assert!(VersionCode::try_new(0).is_err());
assert!(VersionCode::try_new(2_100_000_001).is_err());
assert_eq!(VersionCode::try_new(2_100_000_000).unwrap().get(), 2_100_000_000);
}
}