macro_rules! declare_resource_apdus {
(
$(#[$emeta:meta])*
$vis:vis enum $name:ident $(<$lt:lifetime>)? ($what:literal) {
$( $(#[$vmeta:meta])* $variant:ident ( $(#[$fmeta:meta])* $inner:ty ) = $tag:path ),+ $(,)?
}
) => {
$(#[$emeta])*
$vis enum $name $(<$lt>)? {
$( $(#[$vmeta])* $variant($(#[$fmeta])* $inner), )+
}
impl $(<$lt>)? $name $(<$lt>)? {
pub const TAGS: &'static [$crate::tag::ApduTag] = &[ $( $tag ),+ ];
#[must_use]
pub fn tag(&self) -> $crate::tag::ApduTag {
match self {
$( Self::$variant(_) => $tag, )+
}
}
pub fn parse(body: & $($lt)? [u8]) -> $crate::error::Result<Self> {
if body.len() < 3 {
return Err($crate::error::Error::BufferTooShort(broadcast_common::error::BufferTooShort {
need: 3,
have: body.len(),
what: concat!($what, " apdu_tag"),
}));
}
let t = $crate::tag::ApduTag::from_bytes(body[0], body[1], body[2]);
match t {
$( $tag => Ok(Self::$variant(<$inner>::parse(body)?)), )+
_ => Err($crate::error::Error::UnexpectedApduTag {
got: t.as_u24(),
expected: Self::TAGS[0].as_u24(),
what: $what,
}),
}
}
}
impl $(<$lt>)? ::broadcast_common::Serialize for $name $(<$lt>)? {
type Error = $crate::error::Error;
fn serialized_len(&self) -> usize {
match self {
$( Self::$variant(o) => o.serialized_len(), )+
}
}
fn serialize_into(&self, buf: &mut [u8]) -> $crate::error::Result<usize> {
match self {
$( Self::$variant(o) => o.serialize_into(buf), )+
}
}
}
const _: () = {
let tags = [ $( $tag.as_u24() ),+ ];
let mut i = 0;
while i < tags.len() {
let mut j = i + 1;
while j < tags.len() {
assert!(
tags[i] != tags[j],
concat!("duplicate apdu_tag in declare_resource_apdus!(", stringify!($name), ")")
);
j += 1;
}
i += 1;
}
};
};
}
pub(crate) use declare_resource_apdus;
macro_rules! declare_empty_apdu {
($ty:ty, $tag:expr, $what:literal) => {
impl<'a> ::broadcast_common::Parse<'a> for $ty {
type Error = $crate::error::Error;
fn parse(bytes: &'a [u8]) -> $crate::error::Result<Self> {
let length_form = $crate::objects::parse_empty_apdu(bytes, $tag, $what)?;
Ok(Self { length_form })
}
}
impl ::broadcast_common::Serialize for $ty {
type Error = $crate::error::Error;
fn serialized_len(&self) -> usize {
$crate::objects::empty_apdu_len(self.length_form)
}
fn serialize_into(&self, buf: &mut [u8]) -> $crate::error::Result<usize> {
$crate::objects::serialize_empty_apdu($tag, self.length_form, buf)
}
}
};
}
pub(crate) use declare_empty_apdu;
macro_rules! declare_opaque_apdu {
($ty:ident, $field:ident, $tag:expr, $what:literal) => {
impl<'a> ::broadcast_common::Parse<'a> for $ty<'a> {
type Error = $crate::error::Error;
fn parse(bytes: &'a [u8]) -> $crate::error::Result<Self> {
let (length_form, body) = $crate::objects::parse_apdu_header(bytes, $tag, $what)?;
Ok(Self {
length_form,
$field: body,
})
}
}
impl ::broadcast_common::Serialize for $ty<'_> {
type Error = $crate::error::Error;
fn serialized_len(&self) -> usize {
$crate::objects::apdu_len(self.$field.len(), self.length_form)
}
fn serialize_into(&self, buf: &mut [u8]) -> $crate::error::Result<usize> {
let body_len = self.$field.len();
let pos =
$crate::objects::write_apdu_header($tag, body_len, self.length_form, buf)?;
buf[pos..pos + body_len].copy_from_slice(self.$field);
Ok(pos + body_len)
}
}
};
}
pub(crate) use declare_opaque_apdu;