1#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
5pub struct StandardId(u16);
6
7impl StandardId {
8 pub const ZERO: Self = Self(0);
10
11 pub const MAX: Self = Self(0x7FF);
13
14 #[inline]
18 pub const fn new(raw: u16) -> Option<Self> {
19 if raw <= 0x7FF {
20 Some(Self(raw))
21 } else {
22 None
23 }
24 }
25
26 #[inline]
31 pub const unsafe fn new_unchecked(raw: u16) -> Self {
32 Self(raw)
33 }
34
35 #[inline]
37 pub fn as_raw(&self) -> u16 {
38 self.0
39 }
40}
41
42#[derive(Debug, Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
44pub struct ExtendedId(u32);
45
46impl ExtendedId {
47 pub const ZERO: Self = Self(0);
49
50 pub const MAX: Self = Self(0x1FFF_FFFF);
52
53 #[inline]
57 pub const fn new(raw: u32) -> Option<Self> {
58 if raw <= 0x1FFF_FFFF {
59 Some(Self(raw))
60 } else {
61 None
62 }
63 }
64
65 #[inline]
70 pub const unsafe fn new_unchecked(raw: u32) -> Self {
71 Self(raw)
72 }
73
74 #[inline]
76 pub fn as_raw(&self) -> u32 {
77 self.0
78 }
79
80 pub fn standard_id(&self) -> StandardId {
82 StandardId((self.0 >> 18) as u16)
84 }
85}
86
87#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
89pub enum Id {
90 Standard(StandardId),
92
93 Extended(ExtendedId),
95}
96
97impl Ord for Id {
112 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
113 let split_id = |id: &Id| {
114 let (standard_id_part, ide_bit, extended_id_part) = match id {
115 Id::Standard(StandardId(x)) => (*x, 0, 0),
116 Id::Extended(x) => (
117 x.standard_id().0,
118 1,
119 x.0 & ((1 << 18) - 1), ),
121 };
122 (standard_id_part, ide_bit, extended_id_part)
123 };
124
125 split_id(self).cmp(&split_id(other))
126 }
127}
128
129impl PartialOrd for Id {
130 fn partial_cmp(&self, other: &Id) -> Option<core::cmp::Ordering> {
131 Some(self.cmp(other))
132 }
133}
134
135impl From<StandardId> for Id {
136 #[inline]
137 fn from(id: StandardId) -> Self {
138 Id::Standard(id)
139 }
140}
141
142impl From<ExtendedId> for Id {
143 #[inline]
144 fn from(id: ExtendedId) -> Self {
145 Id::Extended(id)
146 }
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 #[test]
154 fn standard_id_new() {
155 assert_eq!(
156 StandardId::new(StandardId::MAX.as_raw()),
157 Some(StandardId::MAX)
158 );
159 }
160
161 #[test]
162 fn standard_id_new_out_of_range() {
163 assert_eq!(StandardId::new(StandardId::MAX.as_raw() + 1), None);
164 }
165
166 #[test]
167 fn standard_id_new_unchecked_out_of_range() {
168 let id = StandardId::MAX.as_raw() + 1;
169 assert_eq!(unsafe { StandardId::new_unchecked(id) }, StandardId(id));
170 }
171
172 #[test]
173 fn extended_id_new() {
174 assert_eq!(
175 ExtendedId::new(ExtendedId::MAX.as_raw()),
176 Some(ExtendedId::MAX)
177 );
178 }
179
180 #[test]
181 fn extended_id_new_out_of_range() {
182 assert_eq!(ExtendedId::new(ExtendedId::MAX.as_raw() + 1), None);
183 }
184
185 #[test]
186 fn extended_id_new_unchecked_out_of_range() {
187 let id = ExtendedId::MAX.as_raw() + 1;
188 assert_eq!(unsafe { ExtendedId::new_unchecked(id) }, ExtendedId(id));
189 }
190
191 #[test]
192 fn get_standard_id_from_extended_id() {
193 assert_eq!(
194 Some(ExtendedId::MAX.standard_id()),
195 StandardId::new((ExtendedId::MAX.0 >> 18) as u16)
196 );
197 }
198
199 #[test]
200 fn cmp_id() {
201 assert!(StandardId::ZERO < StandardId::MAX);
202 assert!(ExtendedId::ZERO < ExtendedId::MAX);
203
204 assert!(Id::Standard(StandardId::ZERO) < Id::Extended(ExtendedId::ZERO));
205 assert!(Id::Extended(ExtendedId::ZERO) < Id::Extended(ExtendedId::MAX));
206 assert!(Id::Extended(ExtendedId((1 << 11) - 1)) < Id::Standard(StandardId(1)));
207 assert!(Id::Standard(StandardId(1)) < Id::Extended(ExtendedId::MAX));
208 }
209}