1use nutype::nutype;
2
3#[nutype(
8 const_fn,
9 validate(greater_or_equal = 1, less_or_equal = 2_147_483_647),
10 derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Display, TryFrom, Into, FromStr)
11)]
12pub struct ApiLevel(u32);
13
14macro_rules! api_levels {
15 ($($name:ident = $level:literal,)+) => {
16 impl ApiLevel {
17 $(pub const $name: Self = match Self::try_new($level) {
18 Ok(level) => level,
19 Err(_) => panic!("invalid API level constant"),
20 };)+
21 }
22 };
23}
24
25api_levels! {
26 BASE = 1,
27 GINGERBREAD = 9,
28 JELLY_BEAN_MR2 = 18,
29 KITKAT = 19,
30 LOLLIPOP = 21,
31 M = 23,
32 N = 24,
33 O = 26,
34 P = 28,
35 Q = 29,
36 R = 30,
37 S = 31,
38 TIRAMISU = 33,
39 UPSIDE_DOWN_CAKE = 34,
40 VANILLA_ICE_CREAM = 35,
41 BAKLAVA = 36,
42}
43
44impl ApiLevel {
45 pub const fn get(self) -> u32 {
46 self.into_inner()
47 }
48}
49
50#[nutype(
52 const_fn,
53 validate(greater_or_equal = 1, less_or_equal = 2_100_000_000),
54 derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Display, TryFrom, Into, FromStr)
55)]
56pub struct VersionCode(u32);
57
58impl VersionCode {
59 pub const ONE: Self = match Self::try_new(1) {
60 Ok(code) => code,
61 Err(_) => panic!("invalid version code constant"),
62 };
63
64 pub const fn get(self) -> u32 {
65 self.into_inner()
66 }
67}
68
69impl Default for VersionCode {
70 fn default() -> Self {
71 Self::ONE
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn bounds() {
81 assert!(matches!(ApiLevel::try_new(0), Err(ApiLevelError::GreaterOrEqualViolated)));
82 assert!(matches!(ApiLevel::try_new(i32::MAX as u32 + 1), Err(ApiLevelError::LessOrEqualViolated)));
83 assert_eq!(ApiLevel::try_new(24).unwrap(), ApiLevel::N);
84 assert!(VersionCode::try_new(0).is_err());
85 assert!(VersionCode::try_new(2_100_000_001).is_err());
86 assert_eq!(VersionCode::try_new(2_100_000_000).unwrap().get(), 2_100_000_000);
87 }
88}