use super::{ResponseStatusWords, authenticate::AuthenticationRequest, register::RegisterRequest};
#[derive(Debug)]
pub enum Command {
Register,
Authenticate,
Version,
Unsuported(u8),
}
impl From<Command> for u8 {
fn from(src: Command) -> Self {
match src {
Command::Register => 0x01,
Command::Authenticate => 0x02,
Command::Version => 0x03,
Command::Unsuported(cmd) => cmd,
}
}
}
impl From<u8> for Command {
fn from(src: u8) -> Self {
match src {
0x01 => Command::Register,
0x02 => Command::Authenticate,
0x03 => Command::Version,
cmd => Command::Unsuported(cmd),
}
}
}
#[derive(Debug)]
pub enum RequestPayload {
Register(RegisterRequest),
Authenticate(AuthenticationRequest),
Version,
}
#[derive(Debug)]
pub struct Request {
pub cla: u8,
pub ins: Command,
pub p1: u8,
pub data_len: usize,
pub data: RequestPayload,
}
const REQUEST_HEADER_LEN: usize = 6;
impl TryFrom<&[u8]> for Request {
type Error = ResponseStatusWords;
#[expect(clippy::as_conversions)]
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() < REQUEST_HEADER_LEN {
return Err(ResponseStatusWords::WrongLength);
}
let cla = value[0];
if cla != 0 {
return Err(ResponseStatusWords::WrongData);
}
let ins = Command::from(value[1]);
let p1 = value[2];
let data_start = REQUEST_HEADER_LEN + 1;
let data_len = u32::from_be_bytes(value[3..data_start].try_into().unwrap()) as usize;
let data_end = data_start + data_len;
let payload = &value[data_start..data_end];
let data = match ins {
Command::Register => RequestPayload::Register(
payload
.try_into()
.map_err(|_| ResponseStatusWords::WrongLength)?,
),
Command::Authenticate => RequestPayload::Authenticate(
AuthenticationRequest::try_from(payload, p1)
.map_err(|_| ResponseStatusWords::WrongLength)?,
),
Command::Version => RequestPayload::Version,
Command::Unsuported(_) => return Err(ResponseStatusWords::InsNotSupported),
};
Ok(Request {
cla,
ins,
p1,
data_len,
data,
})
}
}