vmbus_core/protocol/
macros.rsmacro_rules! vmbus_message_type {
(pub enum $enum_name:ident, $open_enum_name:ident { $( $num:literal $name:ident $rest:tt, )* }) => {
open_enum! {
#[derive(IntoBytes, FromBytes, Immutable, KnownLayout)]
pub enum $open_enum_name: u32 {
$($name = $num,)*
}
}
}
}
macro_rules! vmbus_message_enum {
(pub enum $enum_name:ident, $open_enum_name:ident { $( $num:literal $name:ident { $($type:ident $min_version:tt $($condition_name:ident:$condition_value:tt)*),* } ,)* }) => {
#[derive(Debug)]
pub enum $enum_name<'a> {
$( $($type($type, &'a [u8]),)* )*
}
impl<'a> $enum_name<'a> {
pub fn parse(data: &'a [u8], version: Option<VersionInfo>) -> Result<Self, ParseError> {
let (version, features) = if let Some(version) = version {
(Some(version.version), version.feature_flags)
} else {
(None, FeatureFlags::new())
};
let (header, data) = MessageHeader::read_from_prefix(data).map_err(|_| ParseError::MessageTooSmall(None))?;
let message = match header.message_type {
$(
$($open_enum_name::$name
if vmbus_message_enum!(@create_conditions $type version features data $min_version $($condition_name:$condition_value)*) =>
{
let (message, remaining) = $type::read_from_prefix(data).map_err(|_| ParseError::MessageTooSmall(Some(header.message_type)))?;
Self::$type(message, remaining)
})*
)*
_ => return Err(ParseError::InvalidMessageType(header.message_type)),
};
Ok(message)
}
}
};
(@create_conditions $type:ident $version_ident:ident $features_ident:ident $data_ident:ident $min_version:tt $($name:ident:$value:tt)*) => {
$version_ident >= vmbus_message_enum!(@to_version $min_version)
$(&& vmbus_message_enum!(@create_condition $type $features_ident $data_ident $name $value))*
};
(@create_condition $type:ident $features_ident:ident $data_ident:ident features $min_features:tt) => {
vmbus_message_enum!(@to_features $features_ident $min_features)
};
(@create_condition $type:ident $features_ident:ident $data_ident:ident check_size true) => {
$data_ident.len() >= size_of::<$type>()
};
(@to_version 0) => { None };
(@to_version $version:ident) => { Some(Version::$version) };
(@to_features $features_ident:ident $flag:ident) => { $features_ident.$flag() };
(@to_features $features_ident:ident ($flag1:ident | $flag2:ident)) => { ($features_ident.$flag1() || $features_ident.$flag2()) };
}
macro_rules! vmbus_message_trait_impl {
(pub enum $enum_name:ident, $open_enum_name:ident { $( $num:literal $name:ident { $($type:ident $min_version:tt $($condition_name:ident:$condition_value:tt)*),* } ,)* }) => {
$($(
impl VmbusMessage for $type {
const MESSAGE_TYPE: $open_enum_name = $open_enum_name::$name;
}
static_assertions::const_assert!($type::MESSAGE_SIZE <= MAX_MESSAGE_SIZE);
)*)*
}
}
macro_rules! vmbus_messages {
($($contents:tt)*) => {
vmbus_message_type!($($contents)*);
vmbus_message_enum!($($contents)*);
vmbus_message_trait_impl!($($contents)*);
}
}