1use core::fmt;
16
17macro_rules! id_newtype {
18 ($(#[$meta:meta])* $name:ident) => {
19 $(#[$meta])*
20 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
21 pub struct $name(u32);
22
23 impl $name {
24 #[must_use]
26 pub const fn new(value: u32) -> Self {
27 Self(value)
28 }
29
30 #[must_use]
32 pub const fn value(self) -> u32 {
33 self.0
34 }
35
36 #[must_use]
38 pub const fn checked_next(self) -> Option<Self> {
39 match self.0.checked_add(1) {
40 Some(v) => Some(Self(v)),
41 None => None,
42 }
43 }
44
45 #[must_use]
47 pub const fn wrapping_next(self) -> Self {
48 Self(self.0.wrapping_add(1))
49 }
50
51 #[must_use]
53 pub const fn saturating_next(self) -> Self {
54 Self(self.0.saturating_add(1))
55 }
56
57 #[must_use]
59 pub const fn checked_add(self, n: u32) -> Option<Self> {
60 match self.0.checked_add(n) {
61 Some(v) => Some(Self(v)),
62 None => None,
63 }
64 }
65
66 #[must_use]
68 pub const fn checked_sub(self, n: u32) -> Option<Self> {
69 match self.0.checked_sub(n) {
70 Some(v) => Some(Self(v)),
71 None => None,
72 }
73 }
74
75 #[must_use]
77 pub const fn checked_distance_from(self, earlier: Self) -> Option<u32> {
78 self.0.checked_sub(earlier.0)
79 }
80 }
81
82 impl fmt::Debug for $name {
83 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
84 fmt::Debug::fmt(&self.0, f)
85 }
86 }
87
88 impl fmt::Display for $name {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 fmt::Display::fmt(&self.0, f)
91 }
92 }
93 };
94}
95
96id_newtype! {
97 SegmentSeq
101}
102
103id_newtype! {
104 PartIndex
106}
107
108#[cfg(test)]
109mod tests {
110 extern crate alloc;
111 use super::*;
112 use alloc::format;
113
114 #[test]
115 fn checked_next_stops_at_max_wrapping_wraps() {
116 let max = SegmentSeq::new(u32::MAX);
117 assert_eq!(max.checked_next(), None);
118 assert_eq!(max.wrapping_next(), SegmentSeq::new(0));
119 assert_eq!(max.saturating_next(), max);
120 assert_eq!(SegmentSeq::new(6).checked_next(), Some(SegmentSeq::new(7)));
121 assert_eq!(PartIndex::new(u32::MAX).checked_next(), None);
122 }
123
124 #[test]
125 fn checked_add_sub_distance() {
126 let s = SegmentSeq::new(5);
127 assert_eq!(s.checked_add(u32::MAX), None);
128 assert_eq!(s.checked_sub(6), None);
129 assert_eq!(s.checked_sub(5), Some(SegmentSeq::new(0)));
130 assert_eq!(s.checked_distance_from(SegmentSeq::new(2)), Some(3));
131 assert_eq!(s.checked_distance_from(SegmentSeq::new(9)), None);
132 }
133
134 #[test]
135 fn display_and_debug_are_bare() {
136 assert_eq!(
137 format!("{} {:?}", PartIndex::new(7), SegmentSeq::new(9)),
138 "7 9"
139 );
140 }
141}