1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//! Attribute macro for ranged number newtypes.
/// Creates a ranged number newtype, along with various helpers.
///
/// ```rust
/// # use ambit_macros::ambit;
/// #[ambit(range = "0..=10")]
/// pub struct ZeroToTen;
/// ```
///
/// Generates:
///
/// ```rust
/// #[repr(transparent)]
/// pub struct ZeroToTen(u8);
/// impl ZeroToTen {
/// pub const MIN_VALUE: u8 = 0;
/// pub const MAX_VALUE: u8 = 10;
/// pub const MIN: Self = unsafe { Self::new_unchecked(0) };
/// pub const MAX: Self = unsafe { Self::new_unchecked(10) };
/// pub fn iter() -> ZeroToTenIter {
/// ZeroToTenIter(Some(Self::MIN))
/// }
/// pub const fn new(n: u8) -> Result<Self, ZeroToTenError> {
/// if n < 0 || n > 10 {
/// return Err(ZeroToTenError(n));
/// }
/// Ok(unsafe { Self::new_unchecked(n) })
/// }
/// pub const unsafe fn new_unchecked(n: u8) -> Self {
/// Self(n)
/// }
/// pub const fn value(&self) -> u8 {
/// self.0
/// }
/// pub const fn is_min(&self) -> bool {
/// self.value() == Self::MIN.value()
/// }
/// pub const fn is_max(&self) -> bool {
/// self.value() == Self::MAX.value()
/// }
/// pub fn pred(&self) -> Option<Self> {
/// (!self.is_min()).then(|| unsafe { Self::new_unchecked(self.value() - 1) })
/// }
/// pub fn succ(&self) -> Option<Self> {
/// (!self.is_max()).then(|| unsafe { Self::new_unchecked(self.value() + 1) })
/// }
/// }
///
/// impl PartialEq<u8> for ZeroToTen {
/// fn eq(&self, &other: &u8) -> bool {
/// self.value() == other
/// }
/// }
///
/// impl TryFrom<u8> for ZeroToTen {
/// type Error = ZeroToTenError;
/// fn try_from(n: u8) -> Result<Self, ZeroToTenError> {
/// Self::new(n)
/// }
/// }
///
/// pub struct ZeroToTenIter(Option<ZeroToTen>);
///
/// impl Iterator for ZeroToTenIter {
/// type Item = ZeroToTen;
/// fn next(&mut self) -> Option<ZeroToTen> {
/// if let Some(next) = self.0.as_ref()?.succ() {
/// self.0.replace(next)
/// } else {
/// self.0.take()
/// }
/// }
/// }
///
/// #[derive(Debug)]
/// #[non_exhaustive]
/// pub struct ZeroToTenError(pub u8);
///
/// impl std::error::Error for ZeroToTenError {}
///
/// impl std::fmt::Display for ZeroToTenError {
/// fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
/// f.write_fmt(format_args!("invalid ZeroToTen: {0}", self.0))
/// }
/// }
///
/// #[macro_export]
/// macro_rules! zerototen {
/// (0) => { unsafe { Self::new_unchecked(0) } };
/// (1) => { unsafe { Self::new_unchecked(1) } };
/// (2) => { unsafe { Self::new_unchecked(2) } };
/// (3) => { unsafe { Self::new_unchecked(3) } };
/// (4) => { unsafe { Self::new_unchecked(4) } };
/// (5) => { unsafe { Self::new_unchecked(5) } };
/// (6) => { unsafe { Self::new_unchecked(6) } };
/// (7) => { unsafe { Self::new_unchecked(7) } };
/// (8) => { unsafe { Self::new_unchecked(8) } };
/// (9) => { unsafe { Self::new_unchecked(9) } };
/// (10) => { unsafe { Self::new_unchecked(10) } };
/// }
/// ```
///
/// The provided range must be an ascending range of unsigned integers. Inclusive (`..`)
/// and exclusive (`..=`) ranges are both supported. The internal type (`u8`, etc) of the newtype
/// will be inferred from the range. If the range does not include zero, the internal type will be
/// a `NonZero`.
///
/// The generated code is not otherwise configurable. I may expand this in the future, in particular
/// adding a way to turn off various parts (the macro_rules, iterators).
pub use ambit;