macro_rules! impl_mcumgr_command {
(@direction read) => {false};
(@direction write) => {true};
(($direction:tt, $groupid:ident, $commandid:literal): $request:ty => $response:ty) => {
impl McuMgrCommand for $request {
type Payload = Self;
type Response = $response;
fn is_write_operation(&self) -> bool {
impl_mcumgr_command!(@direction $direction)
}
fn group_id(&self) -> u16 {
$crate::MCUmgrGroup::$groupid as u16
}
fn command_id(&self) -> u8 {
$commandid
}
fn data(&self) -> &Self {
self
}
}
};
}
pub(super) use impl_mcumgr_command;
#[cfg(test)]
macro_rules! command_encode_decode_test {
(@is_write 0) => {false};
(@is_write 2) => {true};
($name:ident, ($op:tt, $group_id:literal, $command_id:literal), $request:expr, $encoded_req:expr ,$encoded_res:expr, $response:expr $(,)?) => {
#[test]
fn $name() {
use $crate::commands::McuMgrCommand;
let expected_is_write = command_encode_decode_test!(@is_write $op);
assert_eq!($request.is_write_operation(), expected_is_write);
assert_eq!($request.group_id(), $group_id);
assert_eq!($request.command_id(), $command_id);
let mut encoded_request = vec![];
::ciborium::into_writer(&$request.data(), &mut encoded_request).unwrap();
let mut expected_encoded_request = vec![];
::ciborium::into_writer(&$encoded_req.unwrap(), &mut expected_encoded_request).unwrap();
assert_eq!(
hex::encode(encoded_request),
hex::encode(expected_encoded_request),
"encoding mismatch"
);
let mut encoded_response = vec![];
::ciborium::into_writer(&$encoded_res.unwrap(), &mut encoded_response).unwrap();
fn types_match<T: $crate::commands::McuMgrCommand>(
_req: T,
_res: <T as $crate::commands::McuMgrCommand>::Response,
) {
}
types_match($request, $response);
let response = ::ciborium::from_reader(encoded_response.as_slice()).unwrap();
let expected_response = $response;
assert_eq!(response, expected_response, "decoding mismatch");
types_match($request, response);
}
};
}
#[cfg(test)]
pub(super) use command_encode_decode_test;
macro_rules! impl_serialize_as_empty_map {
($type:ty) => {
impl ::serde::Serialize for $type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ::serde::Serializer,
{
const _: () = [()][size_of::<$type>()];
use ::serde::ser::SerializeMap;
let map = serializer.serialize_map(Some(0))?;
map.end()
}
}
};
}
macro_rules! impl_deserialize_from_empty_map_and_into_unit {
($type:ty) => {
impl From<$type> for () {
fn from(_: $type) -> () {
const _: () = [()][size_of::<$type>()]; }
}
impl<'de> ::serde::Deserialize<'de> for $type {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: ::serde::Deserializer<'de>,
{
struct InternalVisitor;
impl<'de> ::serde::de::Visitor<'de> for InternalVisitor {
type Value = $type;
fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "an empty map/object (`{{}}`)")
}
fn visit_map<M>(self, mut map: M) -> Result<$type, M::Error>
where
M: ::serde::de::MapAccess<'de>,
{
let mut had_entries = false;
while map
.next_entry::<::serde::de::IgnoredAny, ::serde::de::IgnoredAny>()?
.is_some()
{
had_entries = true;
}
if had_entries {
::log::debug!(
"Ignoring unexpected entries in unit-type deserialization"
);
}
Ok(<$type>::default())
}
}
deserializer.deserialize_map(InternalVisitor)
}
}
};
}
pub(super) use impl_deserialize_from_empty_map_and_into_unit;
pub(super) use impl_serialize_as_empty_map;