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
108id_newtype! {
109 Generation
112}
113
114#[cfg(test)]
115mod tests {
116 extern crate alloc;
117 use super::*;
118 use alloc::format;
119
120 #[test]
121 fn checked_next_stops_at_max_wrapping_wraps() {
122 let max = SegmentSeq::new(u32::MAX);
123 assert_eq!(max.checked_next(), None);
124 assert_eq!(max.wrapping_next(), SegmentSeq::new(0));
125 assert_eq!(max.saturating_next(), max);
126 assert_eq!(SegmentSeq::new(6).checked_next(), Some(SegmentSeq::new(7)));
127 assert_eq!(PartIndex::new(u32::MAX).checked_next(), None);
128 }
129
130 #[test]
131 fn checked_add_sub_distance() {
132 let s = SegmentSeq::new(5);
133 assert_eq!(s.checked_add(u32::MAX), None);
134 assert_eq!(s.checked_sub(6), None);
135 assert_eq!(s.checked_sub(5), Some(SegmentSeq::new(0)));
136 assert_eq!(s.checked_distance_from(SegmentSeq::new(2)), Some(3));
137 assert_eq!(s.checked_distance_from(SegmentSeq::new(9)), None);
138 }
139
140 #[test]
141 fn display_and_debug_are_bare() {
142 assert_eq!(
143 format!("{} {:?}", PartIndex::new(7), SegmentSeq::new(9)),
144 "7 9"
145 );
146 }
147}