use std::{cmp, fmt};
use crate::constants::IdentifierFlags;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
pub struct StandardId {
identifier: u16,
flags: IdentifierFlags,
}
impl StandardId {
pub const ZERO: Self = Self {
identifier: 0,
flags: IdentifierFlags::empty(),
};
pub const MAX: Self = Self {
identifier: 0x7FF,
flags: IdentifierFlags::empty(),
};
#[inline]
pub const fn new(identifier: u16) -> Option<Self> {
if identifier <= Self::MAX.as_raw() {
Some(Self {
identifier,
flags: IdentifierFlags::empty(),
})
} else {
None
}
}
#[inline]
pub const fn with_flags(identifier: u16, flags: IdentifierFlags) -> Option<Self> {
if identifier <= Self::MAX.as_raw() {
Some(Self {
identifier,
flags: flags.difference(IdentifierFlags::EXTENDED),
})
} else {
None
}
}
#[inline]
pub const fn as_raw(&self) -> u16 {
self.identifier
}
#[inline]
pub const fn flags(&self) -> IdentifierFlags {
self.flags
}
#[inline]
pub const fn set_flags(self, flags: IdentifierFlags) -> Self {
Self {
identifier: self.identifier,
flags,
}
}
#[inline]
pub fn map_flags<F>(self, f: F) -> Self
where
F: FnOnce(IdentifierFlags) -> IdentifierFlags,
{
Self {
identifier: self.identifier,
flags: f(self.flags),
}
}
#[inline]
pub const fn as_extended_id(&self) -> ExtendedId {
ExtendedId {
identifier: self.identifier as u32,
flags: self.flags.union(IdentifierFlags::EXTENDED),
}
}
}
impl fmt::Display for StandardId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let flags = if self.flags.is_empty() {
String::new()
} else {
format!("({:?})", self.flags)
};
write!(f, "{:#X}{}", self.identifier, flags)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd)]
pub struct ExtendedId {
identifier: u32,
flags: IdentifierFlags,
}
impl ExtendedId {
pub const ZERO: Self = Self {
identifier: 0,
flags: IdentifierFlags::EXTENDED,
};
pub const MAX: Self = Self {
identifier: 0x1FFF_FFFF,
flags: IdentifierFlags::EXTENDED,
};
#[inline]
pub const fn new(identifier: u32) -> Option<Self> {
if identifier <= Self::MAX.identifier {
Some(Self {
identifier,
flags: IdentifierFlags::EXTENDED,
})
} else {
None
}
}
#[inline]
pub const fn with_flags(identifier: u32, flags: IdentifierFlags) -> Option<Self> {
if identifier <= Self::MAX.as_raw() {
Some(Self {
identifier,
flags: flags.union(IdentifierFlags::EXTENDED),
})
} else {
None
}
}
#[inline]
pub const fn as_raw(&self) -> u32 {
self.identifier
}
#[inline]
pub const fn flags(&self) -> IdentifierFlags {
self.flags
}
#[inline]
pub const fn set_flags(self, flags: IdentifierFlags) -> Self {
Self {
identifier: self.identifier,
flags,
}
}
#[inline]
pub fn map_flags<F>(self, f: F) -> Self
where
F: FnOnce(IdentifierFlags) -> IdentifierFlags,
{
Self {
identifier: self.identifier,
flags: f(self.flags),
}
}
pub const fn as_standard_id(&self) -> StandardId {
StandardId {
identifier: (self.identifier >> 18) as u16,
flags: self.flags.difference(IdentifierFlags::EXTENDED),
}
}
}
impl fmt::Display for ExtendedId {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let flags = if self.flags.is_empty() {
String::new()
} else {
format!("({:?})", self.flags)
};
write!(f, "{:#X}{}", self.identifier, flags)
}
}
#[derive(Debug, Copy, Clone, Eq, Hash, PartialEq)]
pub enum Id {
Standard(StandardId),
Extended(ExtendedId),
}
impl Id {
pub const fn as_raw(&self) -> u32 {
match self {
Self::Standard(sid) => sid.as_raw() as u32,
Self::Extended(eid) => eid.as_raw(),
}
}
pub const fn flags(&self) -> IdentifierFlags {
match self {
Self::Standard(id) => id.flags(),
Self::Extended(id) => id.flags(),
}
}
#[inline]
pub fn map_flags<F>(self, f: F) -> Self
where
F: FnOnce(IdentifierFlags) -> IdentifierFlags,
{
match self {
Self::Standard(id) => Self::Standard(id.map_flags(f)),
Self::Extended(id) => Self::Extended(id.map_flags(f)),
}
}
}
impl PartialOrd for Id {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
match (self, other) {
(Id::Standard(s1), Id::Standard(s2)) => s1.partial_cmp(s2),
(Id::Standard(_), Id::Extended(_)) => Some(cmp::Ordering::Less),
(Id::Extended(_), Id::Standard(_)) => Some(cmp::Ordering::Greater),
(Id::Extended(e1), Id::Extended(e2)) => e1.partial_cmp(e2),
}
}
}
impl fmt::Display for Id {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Standard(sid) => sid.fmt(f),
Self::Extended(eid) => eid.fmt(f),
}
}
}
impl From<StandardId> for Id {
#[inline]
fn from(id: StandardId) -> Self {
Id::Standard(id)
}
}
impl From<ExtendedId> for Id {
#[inline]
fn from(id: ExtendedId) -> Self {
Id::Extended(id)
}
}
#[cfg(feature = "embedded-can-compat")]
#[cfg_attr(docsrs, doc(cfg(feature = "embedded-can-compat")))]
impl Into<embedded_can::StandardId> for StandardId {
fn into(self) -> embedded_can::StandardId {
unsafe { embedded_can::StandardId::new_unchecked(self.identifier) }
}
}
#[cfg(feature = "embedded-can-compat")]
#[cfg_attr(docsrs, doc(cfg(feature = "embedded-can-compat")))]
impl Into<embedded_can::ExtendedId> for ExtendedId {
fn into(self) -> embedded_can::ExtendedId {
unsafe { embedded_can::ExtendedId::new_unchecked(self.identifier) }
}
}
#[cfg(feature = "embedded-can-compat")]
#[cfg_attr(docsrs, doc(cfg(feature = "embedded-can-compat")))]
impl Into<embedded_can::Id> for Id {
fn into(self) -> embedded_can::Id {
match self {
Self::Standard(sid) => embedded_can::Id::Standard(sid.into()),
Self::Extended(eid) => embedded_can::Id::Extended(eid.into()),
}
}
}