can_socket/
id.rs

1use crate::error::{InvalidId, ParseIdError};
2
3/// The highest valid value for a standard CAN ID.
4pub const MAX_STANDARD_ID: u16 = 0x7FF;
5
6/// The highest valid value for an extended CAN ID.
7pub const MAX_EXTENDED_ID: u32 = 0x1FFF_FFFF;
8
9/// Construct an [`CanId`] (standard or extended) that is checked at compile time.
10///
11/// You can use any expression that can be evaluated at compile time and results in a `u32`.
12///
13/// By default, if the value fits in a standard CAN ID, a standard CAN ID is created.
14/// You can also explicitly ask for a standard or extended ID.
15///
16/// Usage:
17/// ```
18/// # use can_socket::{CanId, can_id};
19/// let id: CanId = can_id!(0x100 | 0x005);
20/// assert2::let_assert!(CanId::Standard(id) = id);
21/// assert2::assert!(id.as_u16() == 0x105);
22/// ```
23///
24/// Force construction of a `CanId::Standard` (does not compile because the ID only fits as an extended ID):
25/// ```compile_fail
26/// # use can_socket::{CanId, can_id};
27/// let id: CanId = id!(standard: 0x10 << 16 | 0x50);
28/// ```
29///
30/// Force construction of a `CanId::Extended`:
31/// ```
32/// # use can_socket::{CanId, can_id};
33/// let id: CanId = can_id!(extended: 0x100 | 0x005);
34/// assert2::let_assert!(CanId::Extended(id) = id);
35/// assert2::assert!(id.as_u32() == 0x105);
36/// ```
37#[macro_export]
38macro_rules! can_id {
39	($n:expr) => {
40		{
41			const N: u32 = ($n);
42			const { ::core::assert!(N <= $crate::MAX_EXTENDED_ID, "invalid CAN ID") };
43			unsafe {
44				if N <= $crate::MAX_STANDARD_ID as u32 {
45					$crate::CanId::Standard($crate::StandardId::new_unchecked(N as u16))
46				} else {
47					$crate::CanId::Extended($crate::ExtendedId::new_unchecked(N))
48				}
49			}
50		}
51	};
52	(standard: $n:expr) => {
53		$crate::CanId::Standard($crate::standard_id!($n))
54	};
55	(extended:  $n:expr) => {
56		$crate::CanId::Extended($crate::extended_id!($n))
57	};
58}
59
60/// Construct a [`StandardId`] that is checked at compile time.
61///
62/// You can use any expression that can be evaluated at compile time and results in a `u16`.
63///
64/// Usage:
65/// ```
66/// # use assert2::assert;
67/// # use can_socket::{StandardId, standard_id};
68/// let id: StandardId = standard_id!(0x100 | 0x005);
69/// assert!(id.as_u16() == 0x105);
70/// ```
71///
72/// Will not accept invalid IDs:
73/// ```compile_fail
74/// # use can_socket::{StandardId, standard_id};
75/// let id: StandardId = standard_id!(0x800);
76/// ```
77#[macro_export]
78macro_rules! standard_id {
79	($n:expr) => {
80		{
81			#[allow(clippy::all)]
82			const { ::core::assert!(($n) <= $crate::MAX_STANDARD_ID, "invalid standard CAN ID") };
83			unsafe {
84				$crate::StandardId::new_unchecked($n)
85			}
86		}
87	};
88}
89
90/// Construct an [`ExtendedId`] that is checked at compile time.
91///
92/// You can use any expression that can be evaluated at compile time and results in a `u32`.
93///
94/// Usage:
95/// ```
96/// # use assert2::assert;
97/// # use can_socket::{ExtendedId, extended_id};
98/// let id: ExtendedId = extended_id!(0x10 << 16 | 0x50);
99/// assert!(id.as_u32() == 0x10_0050);
100/// ```
101///
102/// Will not accept invalid IDs:
103/// ```compile_fail
104/// # use can_socket::{ExtendedId, extended_id};
105/// let id: ExtendedId = extended_id!(0x2000_0000);
106/// ```
107#[macro_export]
108macro_rules! extended_id {
109	($n:expr) => {
110		unsafe {
111			#[allow(clippy::all)]
112			const { ::core::assert!(($n) <= $crate::MAX_EXTENDED_ID, "invalid extended CAN ID"); };
113			$crate::ExtendedId::new_unchecked($n)
114		}
115	};
116}
117
118/// A CAN ID, either standard (11 bit) or extended (29 bits).
119#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
120#[repr(C)]
121pub enum CanId {
122	/// A standard 11 bit CAN ID.
123	Standard(StandardId),
124
125	/// An extended 29 bit CAN ID.
126	Extended(ExtendedId),
127}
128
129/// A standard 11 bit CAN ID.
130#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
131#[repr(transparent)]
132pub struct StandardId {
133	/// The raw ID.
134	id: u16,
135}
136
137/// An extended 29 bit CAN ID.
138#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
139#[repr(transparent)]
140pub struct ExtendedId {
141	/// The raw ID.
142	id: u32,
143}
144
145impl CanId {
146	/// Create a new CAN ID from a raw value.
147	///
148	/// If the value fits in a 11 bit standard CAN ID,
149	/// this function will return [`Self::Standard`].
150	/// a standard ID will be created.
151	///
152	/// Otherwise, if the value fits in a 29 bits extended CAN ID,
153	/// this function returns [`Self::Extended`].
154	///
155	/// If the value doesn't fit in either, this function returns an error.
156	pub const fn new(id: u32) -> Result<Self, InvalidId> {
157		if id <= MAX_STANDARD_ID as u32 {
158			let id = id as u16;
159			Ok(Self::Standard(StandardId { id }))
160		} else {
161			match ExtendedId::new(id) {
162				Ok(x) => Ok(Self::Extended(x)),
163				Err(e) => Err(e)
164			}
165		}
166	}
167
168	/// Create a new standard CAN ID from a raw value.
169	///
170	/// If the value doesn't fit in a standard 11 bit CAN ID,
171	/// this function returns an error.
172	pub const fn new_standard(id: u16) -> Result<Self, InvalidId> {
173		match StandardId::new(id) {
174			Ok(x) => Ok(Self::Standard(x)),
175			Err(e) => Err(e),
176		}
177	}
178
179	/// Create a new extended CAN ID from a raw value.
180	///
181	/// If the value doesn't fit in an extended 29 bit CAN ID,
182	/// this function returns an error.
183	pub const fn new_extended(id: u32) -> Result<Self, InvalidId> {
184		match ExtendedId::new(id) {
185			Ok(x) => Ok(Self::Extended(x)),
186			Err(e) => Err(e),
187		}
188	}
189
190	/// Get the raw value as a `u32`.
191	pub const fn as_u32(self) -> u32 {
192		self.to_extended().as_u32()
193	}
194
195	/// Get `self` as a `StandardId`, or `None` if this is an extended ID.
196	///
197	/// Note: This function always returns `None` if `self` is an extended ID.
198	/// It doesn't matter if the value would have fit in a [`StandardId`].
199	///
200	/// Use [`Self::to_standard()`] if you want to try to convert extended IDs to standard IDs.
201	pub const fn as_standard(self) -> Option<StandardId> {
202		match self {
203			Self::Standard(id) => Some(id),
204			Self::Extended(_) => None,
205		}
206	}
207
208	/// Get `self` as an `ExtendedId`, or `None` if this is a standard ID.
209	///
210	/// Use [`Self::to_extended()`] if you want to convert standard IDs to extended IDs.
211	pub const fn as_extended(self) -> Option<ExtendedId> {
212		match self {
213			Self::Standard(_) => None,
214			Self::Extended(id) => Some(id),
215		}
216	}
217
218	/// Try to convert the ID to a standard ID.
219	///
220	/// Returns an error if the value doesn't fit in a standard ID.
221	pub const fn to_standard(self) -> Result<StandardId, InvalidId> {
222		match self {
223			Self::Standard(id) => Ok(id),
224			Self::Extended(id) => {
225				if id.as_u32() <= u16::MAX as u32 {
226					StandardId::new(id.as_u32() as u16)
227				} else {
228					Err(InvalidId {
229						id: Some(id.as_u32()),
230						extended: false,
231					})
232				}
233			}
234		}
235	}
236
237	/// Convert the ID to an extended ID.
238	pub const fn to_extended(self) -> ExtendedId {
239		match self {
240			Self::Standard(id) => ExtendedId::from_u16(id.as_u16()),
241			Self::Extended(id) => id,
242		}
243	}
244}
245
246impl StandardId {
247	/// The maximum valid standard ID.
248	pub const MAX: Self = Self { id: MAX_STANDARD_ID };
249
250	/// Try to create a new standard ID from a raw value.
251	///
252	/// Returns an error if the value doesn't fit in 11 bits.
253	pub const fn new(id: u16) -> Result<Self, InvalidId> {
254		if id <= MAX_STANDARD_ID {
255			Ok(Self { id })
256		} else {
257			Err(InvalidId {
258				id: Some(id as u32),
259				extended: false,
260			})
261		}
262	}
263
264	/// Create a new standard ID from a `u8`.
265	///
266	/// Note that [`StandardId`] also implements `From<u8>`.
267	/// However, this function is usable in `const` context.
268	pub const fn from_u8(id: u8) -> Self {
269		Self { id: id as u16 }
270	}
271
272	/// Get the raw value as a `u16`.
273	///
274	/// Note that [`StandardId`] also implements `Into<u16>`.
275	/// However, this function is usable in `const` context.
276	pub const fn as_u16(self) -> u16 {
277		self.id
278	}
279
280	/// Create a new standard CAN ID without checking for validity.
281	///
282	/// # Safety
283	/// The given ID must be a valid standard CAN ID (id <= [`MAX_STANDARD_ID`]).
284	pub const unsafe fn new_unchecked(id: u16) -> Self {
285		debug_assert!(id <= MAX_STANDARD_ID);
286		Self {
287			id
288		}
289	}
290}
291
292impl ExtendedId {
293	/// The maximum valid extended ID.
294	pub const MAX: Self = Self { id: MAX_EXTENDED_ID };
295
296	/// Try to create a new extended ID from a raw value.
297	///
298	/// Returns an error if the value doesn't fit in 29 bits.
299	pub const fn new(id: u32) -> Result<Self, InvalidId> {
300		if id <= MAX_EXTENDED_ID {
301			Ok(Self { id })
302		} else {
303			Err(InvalidId {
304				id: Some(id),
305				extended: false,
306			})
307		}
308	}
309
310	/// Create a new extended ID from a `u8`.
311	///
312	/// Note that [`ExtendedId`] also implements `From<u8>`.
313	/// However, this function is usable in `const` context.
314	pub const fn from_u8(id: u8) -> Self {
315		Self { id: id as u32 }
316	}
317
318	/// Create a new extended ID from a `u16`.
319	///
320	/// Note that [`ExtendedId`] also implements `From<u16>`.
321	/// However, this function is usable in `const` context.
322	pub const fn from_u16(id: u16) -> Self {
323		Self { id: id as u32 }
324	}
325
326	/// Get the raw value as a `u32`.
327	///
328	/// Note that [`ExtendedId`] also implements `Into<u32>`.
329	/// However, this function is usable in `const` context.
330	pub const fn as_u32(self) -> u32 {
331		self.id
332	}
333
334	/// Create a new extended CAN ID without checking for validity.
335	///
336	/// # Safety
337	/// The given ID must be a valid extended CAN ID (id <= [`MAX_EXTENDED_ID`]).
338	pub const unsafe fn new_unchecked(id: u32) -> Self {
339		debug_assert!(id <= MAX_EXTENDED_ID);
340		Self {
341			id
342		}
343	}
344}
345
346impl PartialEq<StandardId> for CanId {
347	fn eq(&self, other: &StandardId) -> bool {
348		self.as_standard().is_some_and(|x| x == *other)
349	}
350}
351
352impl PartialEq<CanId> for StandardId {
353	fn eq(&self, other: &CanId) -> bool {
354		other == self
355	}
356}
357
358impl PartialEq<ExtendedId> for CanId {
359	fn eq(&self, other: &ExtendedId) -> bool {
360		self.as_extended().is_some_and(|x| x == *other)
361	}
362}
363
364impl PartialEq<CanId> for ExtendedId {
365	fn eq(&self, other: &CanId) -> bool {
366		other == self
367	}
368}
369
370impl From<u8> for StandardId {
371	fn from(value: u8) -> Self {
372		Self { id: value.into() }
373	}
374}
375
376impl TryFrom<u16> for StandardId {
377	type Error = InvalidId;
378
379	fn try_from(value: u16) -> Result<Self, Self::Error> {
380		Self::new(value)
381	}
382}
383
384impl TryFrom<u32> for StandardId {
385	type Error = InvalidId;
386
387	fn try_from(value: u32) -> Result<Self, Self::Error> {
388		if value > MAX_STANDARD_ID.into() {
389			Err(InvalidId {
390				id: Some(value),
391				extended: false,
392			})
393		} else {
394			Ok(Self { id: value as u16 })
395		}
396	}
397}
398
399impl TryFrom<ExtendedId> for StandardId {
400	type Error = InvalidId;
401
402	fn try_from(value: ExtendedId) -> Result<Self, Self::Error> {
403		Self::try_from(value.as_u32())
404	}
405}
406
407impl TryFrom<CanId> for StandardId {
408	type Error = InvalidId;
409
410	fn try_from(value: CanId) -> Result<Self, Self::Error> {
411		Self::try_from(value.as_u32())
412	}
413}
414
415impl From<u8> for ExtendedId {
416	fn from(value: u8) -> Self {
417		Self { id: value.into() }
418	}
419}
420
421impl From<u16> for ExtendedId {
422	fn from(value: u16) -> Self {
423		Self { id: value.into() }
424	}
425}
426
427impl TryFrom<u32> for ExtendedId {
428	type Error = InvalidId;
429
430	fn try_from(value: u32) -> Result<Self, Self::Error> {
431		Self::new(value)
432	}
433}
434
435impl From<StandardId> for ExtendedId {
436	fn from(value: StandardId) -> Self {
437		value.as_u16().into()
438	}
439}
440
441impl From<CanId> for ExtendedId {
442	fn from(value: CanId) -> Self {
443		value.to_extended()
444	}
445}
446
447impl From<u8> for CanId {
448	fn from(value: u8) -> Self {
449		Self::Standard(value.into())
450	}
451}
452
453impl From<u16> for CanId {
454	fn from(value: u16) -> Self {
455		if value <= MAX_STANDARD_ID {
456			StandardId { id: value }.into()
457		} else {
458			ExtendedId::from(value).into()
459		}
460	}
461}
462
463impl TryFrom<u32> for CanId {
464	type Error = InvalidId;
465
466	fn try_from(value: u32) -> Result<Self, Self::Error> {
467		Self::new(value)
468	}
469}
470
471impl From<StandardId> for CanId {
472	fn from(value: StandardId) -> Self {
473		Self::Standard(value)
474	}
475}
476
477impl From<ExtendedId> for CanId {
478	fn from(value: ExtendedId) -> Self {
479		Self::Extended(value)
480	}
481}
482
483impl std::str::FromStr for StandardId {
484	type Err = ParseIdError;
485
486	fn from_str(input: &str) -> Result<Self, Self::Err> {
487		let id = parse_number(input)
488			.map_err(|e| ParseIdError::invalid_format(e, true))?;
489		let id: u16 = id.try_into()
490			.map_err(|_| ParseIdError::invalid_value(InvalidId { id: Some(id), extended: false }))?;
491		let id = id.try_into()
492			.map_err(|_| ParseIdError::invalid_value(InvalidId { id: Some(id.into()), extended: false }))?;
493		Ok(id)
494	}
495}
496
497impl std::str::FromStr for ExtendedId {
498	type Err = ParseIdError;
499
500	fn from_str(input: &str) -> Result<Self, Self::Err> {
501		let id = parse_number(input)
502			.map_err(|e| ParseIdError::invalid_format(e, true))?;
503		let id = id.try_into()
504			.map_err(|_| ParseIdError::invalid_value(InvalidId { id: Some(id), extended: true }))?;
505		Ok(id)
506	}
507}
508
509impl std::str::FromStr for CanId {
510	type Err = ParseIdError;
511
512	fn from_str(input: &str) -> Result<Self, Self::Err> {
513		let id = parse_number(input)
514			.map_err(|e| ParseIdError::invalid_format(e, true))?;
515		let id = id.try_into()
516			.map_err(|_| ParseIdError::invalid_value(InvalidId { id: Some(id), extended: true }))?;
517		Ok(id)
518	}
519}
520
521fn parse_number(input: &str) -> Result<u32, std::num::ParseIntError> {
522	if let Some(hexadecimal) = input.strip_prefix("0x") {
523		u32::from_str_radix(hexadecimal, 16)
524	} else if let Some(octal) = input.strip_prefix("0o") {
525		u32::from_str_radix(octal, 8)
526	} else if let Some(binary) = input.strip_prefix("0b") {
527		u32::from_str_radix(binary, 2)
528	} else {
529		input.parse()
530	}
531}
532
533impl std::fmt::Debug for CanId {
534	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
535		match self {
536			Self::Standard(id) => id.fmt(f),
537			Self::Extended(id) => id.fmt(f),
538		}
539	}
540}
541
542impl std::fmt::Debug for StandardId {
543	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
544		f.debug_tuple("StandardId")
545			.field(&format_args!("0x{:03X}", self.id))
546			.finish()
547	}
548}
549
550impl std::fmt::Debug for ExtendedId {
551	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
552		f.debug_tuple("ExtendedId")
553			.field(&format_args!("0x{:08X}", self.id))
554			.finish()
555	}
556}
557
558impl std::fmt::LowerHex for StandardId {
559	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
560		self.as_u16().fmt(f)
561	}
562}
563
564impl std::fmt::LowerHex for ExtendedId {
565	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
566		self.as_u32().fmt(f)
567	}
568}
569
570impl std::fmt::LowerHex for CanId {
571	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
572		match self {
573			Self::Standard(x) => x.fmt(f),
574			Self::Extended(x) => x.fmt(f),
575		}
576	}
577}
578
579impl std::fmt::UpperHex for StandardId {
580	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
581		self.as_u16().fmt(f)
582	}
583}
584
585impl std::fmt::UpperHex for ExtendedId {
586	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
587		self.as_u32().fmt(f)
588	}
589}
590
591impl std::fmt::UpperHex for CanId {
592	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
593		match self {
594			Self::Standard(x) => x.fmt(f),
595			Self::Extended(x) => x.fmt(f),
596		}
597	}
598}