macro_rules! enum_builder {
(
$(#[doc = $comment:literal])*
$struct_vis:vis struct $struct_name:ident($inner_vis:vis $uint:ty);
$enum_vis:vis enum $enum_name:ident {
$(
$(#[$enum_metas:meta])*
$enum_var:ident => $enum_val:literal
),*
$(,)?
}
) => {
$(#[doc = $comment])*
#[doc = concat!("(in this case, ", stringify!($uint), ").")]
#[doc = concat!("pub const MyValue: ", stringify!($struct_name), " = ", stringify!($struct_name), "(123);")]
#[allow(missing_docs, clippy::exhaustive_structs)]
#[derive(PartialEq, Eq, Clone, Copy, Hash)]
$struct_vis struct $struct_name($inner_vis $uint);
#[allow(missing_docs, non_upper_case_globals, clippy::upper_case_acronyms)]
impl $struct_name {
#[allow(dead_code)]
$struct_vis fn to_array(self) -> [u8; core::mem::size_of::<$uint>()] {
self.0.to_be_bytes()
}
$(
$(#[$enum_metas])*
$struct_vis const $enum_var: Self = Self($enum_val);
)*
}
impl crate::msgs::Codec<'_> for $struct_name {
fn encode(&self, bytes: &mut alloc::vec::Vec<u8>) {
self.0.encode(bytes);
}
fn read(r: &mut crate::msgs::Reader<'_>) -> Result<Self, crate::error::InvalidMessage> {
match <$uint>::read(r) {
Ok(x) => Ok(Self(x)),
Err(_) => Err(crate::error::InvalidMessage::MissingData(stringify!($struct_name))),
}
}
}
impl core::fmt::Debug for $struct_name {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match $enum_name::try_from(*self) {
Ok(known) => known.fmt(f),
Err(unknown) => write!(f, "0x{:x?}", unknown.0),
}
}
}
impl From<$uint> for $struct_name {
fn from(x: $uint) -> Self {
Self(x)
}
}
impl From<$struct_name> for $uint {
fn from(x: $struct_name) -> Self {
x.0
}
}
$(#[doc = $comment])*
#[allow(missing_docs, non_camel_case_types, clippy::upper_case_acronyms)]
#[non_exhaustive]
#[derive(PartialEq, Eq, Clone, Copy, Debug, Hash)]
$enum_vis enum $enum_name {
$(
$(#[$enum_metas])*
$enum_var = $enum_val
),*
}
impl TryFrom<$struct_name> for $enum_name {
type Error = $struct_name;
fn try_from(value: $struct_name) -> Result<Self, Self::Error> {
match value.0 {
$($enum_val => Ok(Self::$enum_var), )*
_ => Err(value),
}
}
}
};
}
macro_rules! extension_struct {
(
$(#[doc = $comment:literal])*
$struct_vis:vis struct $struct_name:ident$(<$struct_lt:lifetime>)*
{
$(
$(#[$item_attr:meta])*
$item_id:path => $item_vis:vis $item_slot:ident : Option<$item_ty:ty>,
)+
} $( + {
$(
$(#[$meta_attr:meta])*
$meta_vis:vis $meta_slot:ident : $meta_ty:ty,
)+
})*
) => {
$(#[doc = $comment])*
#[non_exhaustive]
#[derive(Clone, Default)]
$struct_vis struct $struct_name$(<$struct_lt>)* {
$(
$(#[$item_attr])*
$item_vis $item_slot: Option<$item_ty>,
)+
$($(
$(#[$meta_attr])*
$meta_vis $meta_slot: $meta_ty,
)+)*
}
impl<'a> $struct_name$(<$struct_lt>)* {
fn read_one(
&mut self,
r: &mut Reader<'a>,
mut unknown: impl FnMut(ExtensionType) -> Result<(), InvalidMessage>,
) -> Result<ExtensionType, InvalidMessage> {
let typ = ExtensionType::read(r)?;
let len = usize::from(u16::read(r)?);
r.sub(len)?
.all(stringify!($struct_name), |body| {
if !self.read_extension_body(typ, body)? {
unknown(typ)?;
}
Ok(typ)
})
}
fn read_extension_body(
&mut self,
typ: ExtensionType,
r: &mut Reader<'a>,
) -> Result<bool, InvalidMessage> {
match typ {
$(
$item_id => Self::read_once(r, $item_id, &mut self.$item_slot)?,
)*
_ => {
r.rest();
return Ok(false);
}
}
Ok(true)
}
fn read_once<T>(r: &mut Reader<'a>, id: ExtensionType, out: &mut Option<T>) -> Result<(), InvalidMessage>
where T: Codec<'a>,
{
if let Some(_) = out {
return Err(InvalidMessage::DuplicateExtension(u16::from(id)));
}
*out = Some(T::read(r)?);
Ok(())
}
fn encode_one(
&self,
typ: ExtensionType,
output: &mut Vec<u8>,
) {
match typ {
$(
$item_id => if let Some(item) = &self.$item_slot {
typ.encode(output);
item.encode(LengthPrefixedBuffer::new(ListLength::U16, output).buf);
},
)*
_ => {},
}
}
#[allow(dead_code)]
pub(crate) fn collect_used(&self) -> Vec<ExtensionType> {
let mut r = Vec::with_capacity(Self::ALL_EXTENSIONS.len());
$(
if let Some(_) = &self.$item_slot {
r.push($item_id);
}
)*
r
}
#[allow(dead_code)]
pub(crate) fn clone_one(
&mut self,
source: &Self,
typ: ExtensionType,
) {
match typ {
$(
$item_id => self.$item_slot = source.$item_slot.clone(),
)*
_ => {},
}
}
#[allow(dead_code)]
pub(crate) fn clear(&mut self, typ: ExtensionType) {
match typ {
$(
$item_id => self.$item_slot = None,
)*
_ => {},
}
}
#[allow(dead_code)]
pub(crate) fn only_contains(&self, allowed: &[ExtensionType]) -> bool {
$(
if let Some(_) = &self.$item_slot {
if !allowed.contains(&$item_id) {
return false;
}
}
)*
true
}
#[allow(dead_code)]
pub(crate) fn contains_any(&self, exts: &[ExtensionType]) -> bool {
for e in exts {
if self.contains(*e) {
return true;
}
}
false
}
fn contains(&self, e: ExtensionType) -> bool {
match e {
$(
$item_id => self.$item_slot.is_some(),
)*
_ => false,
}
}
const ALL_EXTENSIONS: &'static [ExtensionType] = &[
$($item_id,)*
];
}
impl<'a> core::fmt::Debug for $struct_name$(<$struct_lt>)* {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let mut ds = f.debug_struct(stringify!($struct_name));
$(
if let Some(ext) = &self.$item_slot {
ds.field(stringify!($item_slot), ext);
}
)*
$($(
ds.field(stringify!($meta_slot), &self.$meta_slot);
)+)*
ds.finish_non_exhaustive()
}
}
}
}
macro_rules! wrapped_payload(
($(#[$comment:meta])* $vis:vis struct $name:ident, $inner:ident$(<$len:ty, $cardinality:ty>)?,) => {
$(#[$comment])*
#[derive(Clone, Debug)]
$vis struct $name($inner$(<'static, $len, $cardinality>)?);
impl From<Vec<u8>> for $name {
fn from(v: Vec<u8>) -> Self {
Self($inner::from(v))
}
}
impl AsRef<[u8]> for $name {
fn as_ref(&self) -> &[u8] {
self.0.bytes()
}
}
impl Codec<'_> for $name {
fn encode(&self, bytes: &mut Vec<u8>) {
self.0.encode(bytes);
}
fn read(r: &mut Reader<'_>) -> Result<Self, InvalidMessage> {
Ok(Self($inner::read(r)?.into_owned()))
}
}
}
);