oca 0.2.0

An experiment with no_std
Documentation
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct Header {
    pub protocol_version: ProtocolVersion,
    pub pdu_size: PduSize,
    pub pdu_type: PduType,
    pub message_count: MessageCount,
}

impl Header {
    pub const SIZE: usize = 9;
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum ProtocolVersion {
    V1 = 1,
}

#[derive(Debug, thiserror::Error)]
#[error("invalid protocol version {0}")]
pub struct InvalidProtocolVersion(u16);

impl TryFrom<u16> for ProtocolVersion {
    type Error = InvalidProtocolVersion;

    fn try_from(value: u16) -> Result<Self, Self::Error> {
        match value {
            1 => Ok(ProtocolVersion::V1),
            _ => Err(InvalidProtocolVersion(value)),
        }
    }
}

impl From<ProtocolVersion> for u16 {
    fn from(value: ProtocolVersion) -> Self {
        value as u16
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct PduSize(u32);

impl From<u32> for PduSize {
    fn from(value: u32) -> Self {
        PduSize(value)
    }
}

impl From<PduSize> for u32 {
    fn from(PduSize(value): PduSize) -> Self {
        value
    }
}

impl PduSize {
    pub fn size_excluding_header(&self) -> Option<usize> {
        (self.0 as usize).checked_sub(Header::SIZE)
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct MessageCount(u16);

impl MessageCount {
    pub fn is_valid_for_pdu_type(&self, pdu_type: PduType) -> bool {
        match pdu_type {
            PduType::KeepAlive => self.0 == 1,
            _ => true,
        }
    }
}

impl From<MessageCount> for u16 {
    fn from(MessageCount(value): MessageCount) -> Self {
        value
    }
}

#[derive(Debug, thiserror::Error)]
#[error("invalid message count {0}")]
pub struct InvalidMessageCount(pub u16);

impl TryFrom<u16> for MessageCount {
    type Error = InvalidMessageCount;

    fn try_from(value: u16) -> Result<Self, Self::Error> {
        if value > 0 {
            Ok(MessageCount(value))
        } else {
            Err(InvalidMessageCount(value))
        }
    }
}

#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum PduType {
    Command = 0,
    CommandResponseRequired = 1,
    Notification1 = 2,
    Response = 3,
    KeepAlive = 4,
    Notification2 = 5,
}

impl PduType {
    pub const ALL: [PduType; 6] = [
        PduType::Command,
        PduType::CommandResponseRequired,
        PduType::Notification1,
        PduType::Response,
        PduType::KeepAlive,
        PduType::Notification2,
    ];
}

#[derive(Debug, thiserror::Error)]
#[error("invalid pdu type {0}")]
pub struct InvalidPduType(u8);

impl TryFrom<u8> for PduType {
    type Error = InvalidPduType;

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(PduType::Command),
            1 => Ok(PduType::CommandResponseRequired),
            2 => Ok(PduType::Notification1),
            3 => Ok(PduType::Response),
            4 => Ok(PduType::KeepAlive),
            5 => Ok(PduType::Notification2),
            _ => Err(InvalidPduType(value)),
        }
    }
}

impl From<PduType> for u8 {
    fn from(value: PduType) -> Self {
        value as u8
    }
}