use crate::error::{Error, Result};
use crate::tag::{self, ApduTag};
use crate::traits::ApduDef;
use alloc::vec::Vec;
use broadcast_common::{Parse, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct CaInfoEnq;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
pub struct CaInfo {
pub ca_system_ids: Vec<u16>,
}
impl<'a> Parse<'a> for CaInfoEnq {
type Error = Error;
fn parse(bytes: &'a [u8]) -> Result<Self> {
super::parse_empty_apdu(bytes, tag::CA_INFO_ENQ, "ca_info_enq")?;
Ok(Self)
}
}
impl Serialize for CaInfoEnq {
type Error = Error;
fn serialized_len(&self) -> usize {
super::empty_apdu_len()
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
super::serialize_empty_apdu(tag::CA_INFO_ENQ, buf)
}
}
impl ApduDef<'_> for CaInfoEnq {
const TAG: ApduTag = tag::CA_INFO_ENQ;
const NAME: &'static str = "CA_INFO_ENQ";
}
impl<'a> Parse<'a> for CaInfo {
type Error = Error;
fn parse(bytes: &'a [u8]) -> Result<Self> {
let body = super::parse_apdu_header(bytes, tag::CA_INFO, "ca_info")?;
if body.len() % 2 != 0 {
return Err(Error::InvalidObject {
what: "ca_info",
reason: "body length is not a multiple of 2",
});
}
let ca_system_ids = body
.chunks_exact(2)
.map(|c| u16::from_be_bytes([c[0], c[1]]))
.collect();
Ok(Self { ca_system_ids })
}
}
impl Serialize for CaInfo {
type Error = Error;
fn serialized_len(&self) -> usize {
super::apdu_len(self.ca_system_ids.len() * 2)
}
fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
let body_len = self.ca_system_ids.len() * 2;
let mut pos = super::write_apdu_header(tag::CA_INFO, body_len, buf)?;
for id in &self.ca_system_ids {
buf[pos..pos + 2].copy_from_slice(&id.to_be_bytes());
pos += 2;
}
Ok(pos)
}
}
impl ApduDef<'_> for CaInfo {
const TAG: ApduTag = tag::CA_INFO;
const NAME: &'static str = "CA_INFO";
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn enq_round_trip() {
let bytes = CaInfoEnq.to_bytes();
assert_eq!(bytes, [0x9F, 0x80, 0x30, 0x00]);
assert_eq!(CaInfoEnq::parse(&bytes).unwrap(), CaInfoEnq);
}
#[test]
fn ca_info_multi_round_trips() {
let info = CaInfo {
ca_system_ids: alloc::vec![0x0500, 0x0B00, 0x1801],
};
let bytes = info.to_bytes();
assert_eq!(&bytes[..4], &[0x9F, 0x80, 0x31, 0x06]); let parsed = CaInfo::parse(&bytes).unwrap();
assert_eq!(parsed, info);
assert_eq!(parsed.ca_system_ids.len(), 3);
}
#[test]
fn mutating_id_changes_bytes() {
let info = CaInfo {
ca_system_ids: alloc::vec![0x0500],
};
let a = info.to_bytes();
let mut other = info.clone();
other.ca_system_ids[0] = 0x0B00;
assert_ne!(a, other.to_bytes());
}
}