use crate::CanId;
use crate::error;
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct CanFrame {
pub(crate) inner: crate::sys::CanFrame,
}
impl CanFrame {
#[inline]
pub fn new(id: impl Into<CanId>, data: impl Into<CanData>) -> Self {
Self {
inner: crate::sys::CanFrame::new(id, &data.into())
}
}
#[inline]
pub fn try_new<Id, Data>(id: Id, data: Data) -> Result<Self, error::TryNewCanFrameError>
where
Id: TryInto<CanId>,
error::TryNewCanFrameError: From<Id::Error>,
Data: TryInto<CanData>,
error::TryNewCanFrameError: From<Data::Error>,
{
Ok(Self::new(id.try_into()?, data.try_into()?))
}
#[inline]
pub fn new_rtr(id: impl Into<CanId>) -> Self {
Self {
inner: crate::sys::CanFrame::new_rtr(id),
}
}
#[inline]
pub fn id(&self) -> CanId {
self.inner.id()
}
#[inline]
pub fn is_rtr(&self) -> bool {
self.inner.is_rtr()
}
#[inline]
pub fn data(&self) -> Option<CanData> {
self.inner.data()
}
#[inline]
pub fn set_data_length_code(&mut self, dlc: u8) -> Result<(), error::InvalidDataLengthCode> {
self.inner.set_data_length_code(dlc)
.map_err(|()| error::InvalidDataLengthCode { value: dlc })
}
#[inline]
#[must_use = "this function returns a new frame, it does not modify self"]
pub fn with_data_length_code(mut self, dlc: u8) -> Result<Self, error::InvalidDataLengthCode> {
self.set_data_length_code(dlc)?;
Ok(self)
}
#[inline]
pub fn data_length_code(&self) -> u8 {
self.inner.data_length_code()
}
}
impl std::fmt::Debug for CanFrame {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut debug = f.debug_struct("CanFrame");
debug
.field("id", &format_args!("{:?}", self.id()))
.field("is_rtr", &self.is_rtr())
.field("data_length_code", &self.data_length_code());
if !self.is_rtr() {
debug.field("data", &format_args!("{:02X?}", self.data()));
}
debug.finish()
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
pub struct CanData {
pub(crate) data: [u8; 8],
pub(crate) len: u8,
}
impl CanData {
pub fn new(data: impl Into<CanData>) -> Self {
data.into()
}
pub fn try_new<E>(data: impl TryInto<CanData, Error = E>) -> Result<Self, E> {
data.try_into()
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
&self.data[..self.len.into()]
}
#[inline]
pub fn as_slice_mut(&mut self) -> &mut [u8] {
&mut self.data[..self.len.into()]
}
}
impl std::fmt::Debug for CanData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Debug::fmt(self.as_slice(), f)
}
}
impl std::ops::Deref for CanData {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl std::ops::DerefMut for CanData {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_slice_mut()
}
}
impl std::borrow::Borrow<[u8]> for CanData {
fn borrow(&self) -> &[u8] {
self.as_slice()
}
}
impl std::borrow::BorrowMut<[u8]> for CanData {
fn borrow_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
impl AsRef<[u8]> for CanData {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl AsMut<[u8]> for CanData {
fn as_mut(&mut self) -> &mut [u8] {
self.as_slice_mut()
}
}
impl PartialEq<[u8]> for CanData {
fn eq(&self, other: &[u8]) -> bool {
self.as_slice() == other
}
}
impl PartialEq<CanData> for [u8] {
fn eq(&self, other: &CanData) -> bool {
self == other.as_slice()
}
}
macro_rules! impl_from_array {
($n:literal) => {
impl From<[u8; $n]> for CanData {
fn from(value: [u8; $n]) -> Self {
let mut data = [0; 8];
data[..value.len()].copy_from_slice(&value);
Self {
data,
len: $n,
}
}
}
impl<'a> From<&'a [u8; $n]> for CanData {
fn from(value: &'a [u8; $n]) -> Self {
let mut data = [0; 8];
data[..value.len()].copy_from_slice(value);
Self {
data,
len: $n,
}
}
}
impl TryFrom<CanData> for [u8; $n] {
type Error = core::array::TryFromSliceError;
fn try_from(other: CanData) -> Result<Self, Self::Error> {
other.as_slice().try_into()
}
}
impl<'a> TryFrom<&'a CanData> for [u8; $n] {
type Error = core::array::TryFromSliceError;
fn try_from(other: &'a CanData) -> Result<Self, Self::Error> {
other.as_slice().try_into()
}
}
impl PartialEq<[u8; $n]> for CanData {
fn eq(&self, other: &[u8; $n]) -> bool {
if self.len == $n {
&self.data[..$n] == other
} else {
false
}
}
}
impl PartialEq<CanData> for [u8; $n] {
fn eq(&self, other: &CanData) -> bool {
other == self
}
}
}
}
impl_from_array!(0);
impl_from_array!(1);
impl_from_array!(2);
impl_from_array!(3);
impl_from_array!(4);
impl_from_array!(5);
impl_from_array!(6);
impl_from_array!(7);
impl_from_array!(8);
impl TryFrom<&[u8]> for CanData {
type Error = error::TryIntoCanDataError;
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() > 8 {
Err(error::TryIntoCanDataError {
len: value.len(),
})
} else {
let mut data = [0; 8];
data[..value.len()].copy_from_slice(value);
Ok(Self {
data,
len: value.len() as u8,
})
}
}
}
impl TryFrom<&Vec<u8>> for CanData {
type Error = error::TryIntoCanDataError;
fn try_from(value: &Vec<u8>) -> Result<Self, Self::Error> {
value.as_slice().try_into()
}
}
impl TryFrom<&Box<[u8]>> for CanData {
type Error = error::TryIntoCanDataError;
fn try_from(value: &Box<[u8]>) -> Result<Self, Self::Error> {
let value: &[u8] = value;
value.try_into()
}
}
#[cfg(test)]
mod test {
use super::*;
use assert2::assert;
use crate::can_id;
#[test]
fn can_frame_is_copy() {
let frame = CanFrame::new(1u8, [1, 2, 3, 4]);
let copy = frame;
assert!(copy.id() == can_id!(1));
assert!(copy.data() == Some(CanData::new([1, 2, 3, 4])));
}
#[test]
fn can_data_from_array() {
assert!(CanData::from([1]) == [1]);
assert!(CanData::from([1, 2]) == [1, 2]);
assert!(CanData::from([1, 2, 3]) == [1, 2, 3]);
assert!(CanData::from([1, 2, 3, 4, 5]) == [1, 2, 3, 4, 5]);
assert!(CanData::from([1, 2, 3, 4, 5, 6]) == [1, 2, 3, 4, 5, 6]);
assert!(CanData::from([1, 2, 3, 4, 5, 6, 7]) == [1, 2, 3, 4, 5, 6, 7]);
assert!(CanData::from([1, 2, 3, 4, 5, 6, 7, 8]) == [1, 2, 3, 4, 5, 6, 7, 8]);
assert!(CanData::from([1, 2]) != [1]);
assert!(CanData::from([1]) != [1, 2]);
}
}