use crate::constants::{
DO, DONT, SLC_ABORT, SLC_ABORTC, SLC_ACK, SLC_AO, SLC_AYT, SLC_BRK, SLC_BRKC, SLC_DSUSPC,
SLC_EC, SLC_EL, SLC_EOF, SLC_EOFCHAR, SLC_EOR, SLC_EORC, SLC_EW, SLC_EXIT, SLC_FLUSHIN,
SLC_FLUSHOUT, SLC_FORW1, SLC_FORW2, SLC_IP, SLC_LEVELBITS, SLC_LNEXT, SLC_LP, SLC_MCL, SLC_MCR,
SLC_MCUB, SLC_MCUF, SLC_MCWL, SLC_MCWR, SLC_REPRINT, SLC_RP, SLC_SUSP, SLC_SUSPC, SLC_SUSPCHAR,
SLC_SYNCH, SLC_XOFF, SLC_XOFFC, SLC_XON, SLC_XONC, WILL, WONT,
};
#[derive(Debug, PartialEq, Copy, Clone, Eq)]
pub enum Level {
NoSupport,
CantChange,
Value,
Default,
}
impl From<u8> for Level {
fn from(value: u8) -> Self {
match value & SLC_LEVELBITS {
0 => Level::NoSupport,
1 => Level::CantChange,
2 => Level::Value,
3 => Level::Default,
_ => unreachable!("Level value out of range"), }
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ForwardMaskOption {
Do(Vec<u8>),
Dont,
Will,
Wont,
Unknown(u8),
}
impl From<ForwardMaskOption> for u8 {
fn from(val: ForwardMaskOption) -> u8 {
match val {
ForwardMaskOption::Do(_) => DO,
ForwardMaskOption::Dont => DONT,
ForwardMaskOption::Will => WILL,
ForwardMaskOption::Wont => WONT,
ForwardMaskOption::Unknown(byte) => byte,
}
}
}
impl From<u8> for ForwardMaskOption {
fn from(value: u8) -> Self {
match value {
DO => ForwardMaskOption::Do(Vec::with_capacity(16)),
DONT => ForwardMaskOption::Dont,
WILL => ForwardMaskOption::Will,
WONT => ForwardMaskOption::Dont,
byte => ForwardMaskOption::Unknown(byte),
}
}
}
#[derive(Debug, PartialEq, Copy, Clone, Eq)]
pub struct Dispatch {
pub function: SlcFunction,
pub modifiers: Modifiers,
}
impl From<(u8, u8)> for Dispatch {
fn from((function, modifiers): (u8, u8)) -> Self {
Self { function: function.into(), modifiers: modifiers.into() }
}
}
impl From<u8> for Modifiers {
fn from(value: u8) -> Self {
Modifiers {
level: Level::from(value),
ack: value & SLC_ACK != 0,
flush_in: value & SLC_FLUSHIN != 0,
flush_out: value & SLC_FLUSHOUT != 0,
}
}
}
impl From<Dispatch> for (u8, u8) {
fn from(val: Dispatch) -> (u8, u8) {
(val.function.into(), val.modifiers.into())
}
}
#[derive(Debug, PartialEq, Copy, Clone, Eq)]
pub struct Modifiers {
pub level: Level,
pub ack: bool,
pub flush_in: bool,
pub flush_out: bool,
}
impl From<Modifiers> for u8 {
fn from(val: Modifiers) -> u8 {
let mut value: u8 = val.level.into();
if val.ack {
value |= SLC_ACK;
}
if val.flush_in {
value |= SLC_FLUSHIN;
}
if val.flush_out {
value |= SLC_FLUSHOUT;
}
value
}
}
impl From<Level> for u8 {
fn from(val: Level) -> u8 {
match val {
Level::NoSupport => 0,
Level::CantChange => 1,
Level::Value => 2,
Level::Default => 3,
}
}
}
#[repr(u8)]
#[derive(Debug, PartialEq, Eq, Copy, Clone)]
pub enum SlcFunction {
Synch = SLC_SYNCH,
Brk = SLC_BRK,
Ip = SLC_IP,
Ao = SLC_AO,
Ayt = SLC_AYT,
Eor = SLC_EOR,
Abort = SLC_ABORT,
Eof = SLC_EOF,
Susp = SLC_SUSP,
Ec = SLC_EC,
El = SLC_EL,
Ew = SLC_EW,
Rp = SLC_RP,
Lnext = SLC_LNEXT,
Xon = SLC_XON,
Xoff = SLC_XOFF,
Forw1 = SLC_FORW1,
Forw2 = SLC_FORW2,
Mcl = SLC_MCL,
Mcr = SLC_MCR,
Mcwl = SLC_MCWL,
Mcwr = SLC_MCWR,
Mcub = SLC_MCUB,
Mcuf = SLC_MCUF,
Lp = SLC_LP,
Xonc = SLC_XONC,
Xoffc = SLC_XOFFC,
Exit = SLC_EXIT,
Suspc = SLC_SUSPC,
Dsuspc = SLC_DSUSPC,
Reprint = SLC_REPRINT,
Abortc = SLC_ABORTC,
Eofchar = SLC_EOFCHAR,
Suspchar = SLC_SUSPCHAR,
Brkc = SLC_BRKC,
Eorc = SLC_EORC,
Unknown(u8),
}
impl From<u8> for SlcFunction {
fn from(value: u8) -> Self {
match value {
SLC_SYNCH => SlcFunction::Synch,
SLC_BRK => SlcFunction::Brk,
SLC_IP => SlcFunction::Ip,
SLC_AO => SlcFunction::Ao,
SLC_AYT => SlcFunction::Ayt,
SLC_EOR => SlcFunction::Eor,
SLC_ABORT => SlcFunction::Abort,
SLC_EOF => SlcFunction::Eof,
SLC_SUSP => SlcFunction::Susp,
SLC_EC => SlcFunction::Ec,
SLC_EL => SlcFunction::El,
SLC_EW => SlcFunction::Ew,
SLC_RP => SlcFunction::Rp,
SLC_LNEXT => SlcFunction::Lnext,
SLC_XON => SlcFunction::Xon,
SLC_XOFF => SlcFunction::Xoff,
SLC_FORW1 => SlcFunction::Forw1,
SLC_FORW2 => SlcFunction::Forw2,
SLC_MCL => SlcFunction::Mcl,
SLC_MCR => SlcFunction::Mcr,
SLC_MCWL => SlcFunction::Mcwl,
SLC_MCWR => SlcFunction::Mcwr,
SLC_MCUB => SlcFunction::Mcub,
SLC_MCUF => SlcFunction::Mcuf,
SLC_LP => SlcFunction::Lp,
SLC_XONC => SlcFunction::Xonc,
SLC_XOFFC => SlcFunction::Xoffc,
SLC_EXIT => SlcFunction::Exit,
SLC_SUSPC => SlcFunction::Suspc,
SLC_DSUSPC => SlcFunction::Dsuspc,
SLC_REPRINT => SlcFunction::Reprint,
SLC_ABORTC => SlcFunction::Abortc,
SLC_EOFCHAR => SlcFunction::Eofchar,
SLC_SUSPCHAR => SlcFunction::Suspchar,
SLC_BRKC => SlcFunction::Brkc,
SLC_EORC => SlcFunction::Eorc,
_ => SlcFunction::Unknown(value), }
}
}
impl From<SlcFunction> for u8 {
fn from(val: SlcFunction) -> u8 {
match val {
SlcFunction::Synch => SLC_SYNCH,
SlcFunction::Brk => SLC_BRK,
SlcFunction::Ip => SLC_IP,
SlcFunction::Ao => SLC_AO,
SlcFunction::Ayt => SLC_AYT,
SlcFunction::Eor => SLC_EOR,
SlcFunction::Abort => SLC_ABORT,
SlcFunction::Eof => SLC_EOF,
SlcFunction::Susp => SLC_SUSP,
SlcFunction::Ec => SLC_EC,
SlcFunction::El => SLC_EL,
SlcFunction::Ew => SLC_EW,
SlcFunction::Rp => SLC_RP,
SlcFunction::Lnext => SLC_LNEXT,
SlcFunction::Xon => SLC_XON,
SlcFunction::Xoff => SLC_XOFF,
SlcFunction::Forw1 => SLC_FORW1,
SlcFunction::Forw2 => SLC_FORW2,
SlcFunction::Mcl => SLC_MCL,
SlcFunction::Mcr => SLC_MCR,
SlcFunction::Mcwl => SLC_MCWL,
SlcFunction::Mcwr => SLC_MCWR,
SlcFunction::Mcub => SLC_MCUB,
SlcFunction::Mcuf => SLC_MCUF,
SlcFunction::Lp => SLC_LP,
SlcFunction::Xonc => SLC_XONC,
SlcFunction::Xoffc => SLC_XOFFC,
SlcFunction::Exit => SLC_EXIT,
SlcFunction::Suspc => SLC_SUSPC,
SlcFunction::Dsuspc => SLC_DSUSPC,
SlcFunction::Reprint => SLC_REPRINT,
SlcFunction::Abortc => SLC_ABORTC,
SlcFunction::Eofchar => SLC_EOFCHAR,
SlcFunction::Suspchar => SLC_SUSPCHAR,
SlcFunction::Brkc => SLC_BRKC,
SlcFunction::Eorc => SLC_EORC,
SlcFunction::Unknown(value) => value,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parse_slc_function() {
let input = SLC_SYNCH; let expected = SlcFunction::Synch;
let result = SlcFunction::from(input);
assert_eq!(result, expected, "Failed to parse SLC_SYNCH into SlcFunction::Synch");
}
#[test]
fn test_modifiers_from_byte() {
let input = SLC_ACK | SLC_FLUSHIN; let result = Modifiers::from(input);
assert!(
result.ack && result.flush_in,
"Modifiers did not correctly interpret ACK and FLUSHIN flags"
);
}
}