can-socket 0.0.1-alpha2

no frills CAN sockets (blocking or async with tokio)
Documentation
use crate::error::{InvalidId, ParseIdError};

pub const MAX_CAN_ID_BASE: u16 = 0x7FF;
pub const MAX_CAN_ID_EXTENDED: u32 = 0x1FFF_FFFF;

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[repr(C)]
pub enum CanId {
	Base(CanBaseId),
	Extended(CanExtendedId),
}

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[repr(transparent)]
pub struct CanBaseId {
	id: u16,
}

#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd)]
#[repr(transparent)]
pub struct CanExtendedId {
	id: u32,
}

impl CanId {
	pub fn new(id: u32) -> Result<Self, InvalidId> {
		if id <= MAX_CAN_ID_BASE.into() {
			let id = id as u16;
			Ok(Self::Base(CanBaseId { id }))
		} else {
			Ok(Self::Extended(CanExtendedId::new(id)?))
		}
	}

	pub fn new_base(id: u16) -> Result<Self, InvalidId> {
		Ok(Self::Base(CanBaseId::new(id)?))
	}

	pub fn new_extended(id: u32) -> Result<Self, InvalidId> {
		Ok(Self::Extended(CanExtendedId::new(id)?))
	}

	pub fn as_u32(self) -> u32 {
		self.to_extended().as_u32()
	}

	pub fn as_base(self) -> Option<CanBaseId> {
		match self {
			Self::Base(id) => Some(id),
			Self::Extended(_) => None,
		}
	}

	pub fn as_extended(self) -> Option<CanExtendedId> {
		match self {
			Self::Base(_) => None,
			Self::Extended(id) => Some(id),
		}
	}

	pub fn to_base(self) -> Result<CanBaseId, InvalidId> {
		match self {
			Self::Base(id) => Ok(id),
			Self::Extended(id) => id.try_into(),
		}
	}

	pub fn to_extended(self) -> CanExtendedId {
		match self {
			Self::Base(id) => id.into(),
			Self::Extended(id) => id,
		}
	}
}

impl CanBaseId {
	pub fn new(id: u16) -> Result<Self, InvalidId> {
		if id <= MAX_CAN_ID_BASE {
			Ok(Self { id })
		} else {
			Err(InvalidId {
				id: Some(id.into()),
				extended: false,
			})
		}
	}

	pub fn as_u16(self) -> u16 {
		self.id
	}
}

impl CanExtendedId {
	pub fn new(id: u32) -> Result<Self, InvalidId> {
		if id <= MAX_CAN_ID_EXTENDED {
			Ok(Self { id })
		} else {
			Err(InvalidId {
				id: Some(id),
				extended: false,
			})
		}
	}

	pub fn as_u32(self) -> u32 {
		self.id
	}
}

impl PartialEq<CanBaseId> for CanId {
	fn eq(&self, other: &CanBaseId) -> bool {
		self.as_base()
			.map(|x| x == *other)
			.unwrap_or(false)
	}
}

impl PartialEq<CanId> for CanBaseId {
	fn eq(&self, other: &CanId) -> bool {
		other == self
	}
}

impl PartialEq<CanExtendedId> for CanId {
	fn eq(&self, other: &CanExtendedId) -> bool {
		self.as_extended()
			.map(|x| x == *other)
			.unwrap_or(false)
	}
}

impl PartialEq<CanId> for CanExtendedId {
	fn eq(&self, other: &CanId) -> bool {
		other == self
	}
}

impl From<u8> for CanBaseId {
	fn from(value: u8) -> Self {
		Self { id: value.into() }
	}
}

impl TryFrom<u16> for CanBaseId {
	type Error = InvalidId;

	fn try_from(value: u16) -> Result<Self, Self::Error> {
		Self::new(value)
	}
}

impl TryFrom<u32> for CanBaseId {
	type Error = InvalidId;

	fn try_from(value: u32) -> Result<Self, Self::Error> {
		if value > MAX_CAN_ID_BASE.into() {
			Err(InvalidId {
				id: Some(value),
				extended: false,
			})
		} else {
			Ok(Self { id: value as u16 })
		}
	}
}

impl TryFrom<CanExtendedId> for CanBaseId {
	type Error = InvalidId;

	fn try_from(value: CanExtendedId) -> Result<Self, Self::Error> {
		Self::try_from(value.as_u32())
	}
}

impl TryFrom<CanId> for CanBaseId {
	type Error = InvalidId;

	fn try_from(value: CanId) -> Result<Self, Self::Error> {
		Self::try_from(value.as_u32())
	}
}

impl From<u8> for CanExtendedId {
	fn from(value: u8) -> Self {
		Self { id: value.into() }
	}
}

impl From<u16> for CanExtendedId {
	fn from(value: u16) -> Self {
		Self { id: value.into() }
	}
}

impl TryFrom<u32> for CanExtendedId {
	type Error = InvalidId;

	fn try_from(value: u32) -> Result<Self, Self::Error> {
		Self::new(value)
	}
}

impl From<CanBaseId> for CanExtendedId {
	fn from(value: CanBaseId) -> Self {
		value.as_u16().into()
	}
}

impl From<CanId> for CanExtendedId {
	fn from(value: CanId) -> Self {
		value.to_extended()
	}
}

impl From<u8> for CanId {
	fn from(value: u8) -> Self {
		Self::Base(value.into())
	}
}

impl From<u16> for CanId {
	fn from(value: u16) -> Self {
		if value <= MAX_CAN_ID_BASE {
			CanBaseId { id: value }.into()
		} else {
			CanExtendedId::from(value).into()
		}
	}
}

impl TryFrom<u32> for CanId {
	type Error = InvalidId;

	fn try_from(value: u32) -> Result<Self, Self::Error> {
		Self::new(value)
	}
}

impl From<CanBaseId> for CanId {
	fn from(value: CanBaseId) -> Self {
		Self::Base(value)
	}
}

impl From<CanExtendedId> for CanId {
	fn from(value: CanExtendedId) -> Self {
		Self::Extended(value)
	}
}

impl std::str::FromStr for CanBaseId {
	type Err = ParseIdError;

	fn from_str(input: &str) -> Result<Self, Self::Err> {
		let id = parse_number(input)
			.map_err(|e| ParseIdError::invalid_format(e, true))?;
		let id: u16 = id.try_into()
			.map_err(|_| ParseIdError::invalid_value(InvalidId { id: Some(id), extended: false }))?;
		let id = id.try_into()
			.map_err(|_| ParseIdError::invalid_value(InvalidId { id: Some(id.into()), extended: false }))?;
		Ok(id)
	}
}

impl std::str::FromStr for CanExtendedId {
	type Err = ParseIdError;

	fn from_str(input: &str) -> Result<Self, Self::Err> {
		let id = parse_number(input)
			.map_err(|e| ParseIdError::invalid_format(e, true))?;
		let id = id.try_into()
			.map_err(|_| ParseIdError::invalid_value(InvalidId { id: Some(id), extended: true }))?;
		Ok(id)
	}
}

impl std::str::FromStr for CanId {
	type Err = ParseIdError;

	fn from_str(input: &str) -> Result<Self, Self::Err> {
		let id = parse_number(input)
			.map_err(|e| ParseIdError::invalid_format(e, true))?;
		let id = id.try_into()
			.map_err(|_| ParseIdError::invalid_value(InvalidId { id: Some(id), extended: true }))?;
		Ok(id)
	}
}

fn parse_number(input: &str) -> Result<u32, std::num::ParseIntError> {
	if let Some(hexadecimal) = input.strip_prefix("0x") {
		u32::from_str_radix(hexadecimal, 16)
	} else if let Some(octal) = input.strip_prefix("0o") {
		u32::from_str_radix(octal, 8)
	} else if let Some(binary) = input.strip_prefix("0b") {
		u32::from_str_radix(binary, 2)
	} else {
		input.parse()
	}
}

impl std::fmt::Debug for CanId {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		match self {
			Self::Base(id) => id.fmt(f),
			Self::Extended(id) => id.fmt(f),
		}
	}
}

impl std::fmt::Debug for CanBaseId {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		f.debug_tuple("CanBaseId")
			.field(&format_args!("0x{:03X}", self.id))
			.finish()
	}
}

impl std::fmt::Debug for CanExtendedId {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		f.debug_tuple("CanExtendedId")
			.field(&format_args!("0x{:08X}", self.id))
			.finish()
	}
}

impl std::fmt::LowerHex for CanBaseId {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		self.as_u16().fmt(f)
	}
}

impl std::fmt::LowerHex for CanExtendedId {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		self.as_u32().fmt(f)
	}
}

impl std::fmt::LowerHex for CanId {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		match self {
			Self::Base(x) => x.fmt(f),
			Self::Extended(x) => x.fmt(f),
		}
	}
}

impl std::fmt::UpperHex for CanBaseId {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		self.as_u16().fmt(f)
	}
}

impl std::fmt::UpperHex for CanExtendedId {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		self.as_u32().fmt(f)
	}
}

impl std::fmt::UpperHex for CanId {
	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
		match self {
			Self::Base(x) => x.fmt(f),
			Self::Extended(x) => x.fmt(f),
		}
	}
}