can_dbc/ast/
message_id.rs1use can_dbc_pest::{Pair, Rule};
2
3use crate::parser::parse_uint;
4use crate::DbcError;
5
6#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
9#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
10pub enum MessageId {
11 Standard(u16),
12 Extended(u32),
15}
16
17impl MessageId {
18 #[must_use]
20 pub fn raw(self) -> u32 {
21 match self {
22 Self::Standard(id) => u32::from(id),
23 Self::Extended(id) => id | 1 << 31,
24 }
25 }
26}
27
28impl TryFrom<u64> for MessageId {
29 type Error = DbcError;
30
31 fn try_from(value: u64) -> Result<Self, Self::Error> {
32 u32::try_from(value)
33 .map_err(|_| DbcError::MessageIdOutOfRange(value))?
34 .try_into()
35 }
36}
37
38impl TryFrom<u32> for MessageId {
39 type Error = DbcError;
40
41 fn try_from(value: u32) -> Result<Self, Self::Error> {
46 const EXTENDED_ID_FLAG: u32 = 1 << 31;
47 Ok(if value & EXTENDED_ID_FLAG != 0 {
48 Self::Extended(value & 0x1FFF_FFFF)
49 } else {
50 #[allow(clippy::cast_possible_truncation)]
54 let v = value as u16;
55
56 Self::Standard(v)
57 })
58 }
59}
60
61impl TryFrom<Pair<'_, Rule>> for MessageId {
62 type Error = DbcError;
63
64 fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
65 Self::try_from(parse_uint(&value)?)
66 }
67}
68
69#[cfg(test)]
70mod tests {
71 use can_dbc_pest::Rule;
72
73 use crate::test_helpers::*;
74 use crate::MessageId;
75
76 #[test]
77 #[expect(clippy::unreadable_literal)]
78 fn extended_message_id_raw() {
79 let id = MessageId::Extended(2);
80 assert_eq!(id.raw(), 2 | 1 << 31);
81
82 let id = MessageId::Extended(0x1FFF_FFFF);
84 assert_eq!(id.raw(), 0b10011111_11111111_11111111_11111111);
85 }
86
87 #[test]
88 fn standard_message_id_raw() {
89 let id = MessageId::Standard(2);
90 assert_eq!(id.raw(), 2);
91 }
92
93 #[test]
94 fn try_from_u32_standard() {
95 let id = MessageId::try_from(500u32).unwrap();
96 assert_eq!(id, MessageId::Standard(500));
97 }
98
99 #[test]
100 fn try_from_u32_extended() {
101 let id = MessageId::try_from(2u32 | (1 << 31)).unwrap();
102 assert_eq!(id, MessageId::Extended(2));
103 }
104
105 #[test]
106 fn try_from_u64_standard() {
107 let id = MessageId::try_from(500u64).unwrap();
108 assert_eq!(id, MessageId::Standard(500));
109 }
110
111 #[test]
112 fn try_from_u64_extended() {
113 let id = MessageId::try_from(2u64 | (1 << 31)).unwrap();
114 assert_eq!(id, MessageId::Extended(2));
115 }
116
117 #[test]
118 fn standard_message_id_test() {
119 let val = test_into::<MessageId>("2", Rule::message_id);
120 assert_eq!(val, MessageId::Standard(2));
121 }
122
123 #[test]
124 fn extended_low_message_id_test() {
125 let s = (2u32 | 1 << 31).to_string();
126 let val = test_into::<MessageId>(&s, Rule::message_id);
127 assert_eq!(val, MessageId::Extended(2));
128 }
129
130 #[test]
131 fn extended_message_id_test() {
132 let s = (0x1FFF_FFFF_u32 | 1 << 31).to_string();
133 let val = test_into::<MessageId>(&s, Rule::message_id);
134 assert_eq!(val, MessageId::Extended(0x1FFF_FFFF));
135 }
136
137 #[test]
138 fn extended_message_id_test_max_29bit() {
139 let s = u32::MAX.to_string();
140 let val = test_into::<MessageId>(&s, Rule::message_id);
141 assert_eq!(val, MessageId::Extended(0x1FFF_FFFF));
142 }
143}