1#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
12#[repr(transparent)]
13pub struct MsgId(u32);
14
15impl MsgId {
16 #[doc(hidden)]
17 pub const INDEX_BITS: u32 = 24;
19
20 const INDEX_MASK: u32 = (1 << Self::INDEX_BITS) - 1;
21
22 #[doc(hidden)]
23 pub const fn new(chunk: u8, index: u32) -> Option<MsgId> {
25 if index > Self::INDEX_MASK {
26 return None;
27 }
28 Some(MsgId(((chunk as u32) << Self::INDEX_BITS) | index))
29 }
30
31 #[doc(hidden)]
32 pub const fn from_raw(raw: u32) -> MsgId {
34 MsgId(raw)
35 }
36
37 #[doc(hidden)]
38 pub const fn raw(self) -> u32 {
40 self.0
41 }
42
43 #[doc(hidden)]
44 pub const fn chunk(self) -> u8 {
46 #[allow(clippy::cast_possible_truncation)]
48 let chunk = (self.0 >> Self::INDEX_BITS) as u8;
49 chunk
50 }
51
52 #[doc(hidden)]
53 pub const fn index(self) -> u32 {
55 self.0 & Self::INDEX_MASK
56 }
57}
58
59#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
64#[repr(u8)]
65pub enum Dir {
66 Ltr = 0,
68 Rtl = 1,
70 Auto = 2,
72}
73
74#[cfg(test)]
75mod tests {
76 use super::{Dir, MsgId};
77
78 #[test]
79 fn bit_layout() {
80 let id = MsgId::new(0x12, 0x34_5678).expect("index fits");
81 assert_eq!(id.raw(), 0x1234_5678);
82 assert_eq!(id.chunk(), 0x12);
83 assert_eq!(id.index(), 0x34_5678);
84 assert_eq!(MsgId::from_raw(0x1234_5678), id);
85 assert_eq!(MsgId::INDEX_BITS, 24);
86 }
87
88 #[test]
89 fn index_bounds() {
90 assert!(MsgId::new(0, (1 << 24) - 1).is_some());
91 assert!(MsgId::new(0, 1 << 24).is_none());
92 assert!(MsgId::new(255, u32::MAX).is_none());
93 let max = MsgId::new(255, (1 << 24) - 1).expect("fits");
94 assert_eq!(max.raw(), u32::MAX);
95 assert_eq!((max.chunk(), max.index()), (255, 0xFF_FFFF));
96 let zero = MsgId::new(0, 0).expect("fits");
97 assert_eq!(zero.raw(), 0);
98 }
99
100 #[test]
101 fn order_is_chunk_then_index() {
102 let a = MsgId::new(0, 5).expect("fits");
103 let b = MsgId::new(0, 6).expect("fits");
104 let c = MsgId::new(1, 0).expect("fits");
105 assert!(a < b && b < c);
106 }
107
108 #[test]
109 fn dir_discriminants() {
110 assert_eq!(Dir::Ltr as u8, 0);
111 assert_eq!(Dir::Rtl as u8, 1);
112 assert_eq!(Dir::Auto as u8, 2);
113 }
114}