riot_coap_handler_demos/
minicbor_helpers.rsuse core::borrow::Borrow;
#[derive(Debug, Clone)]
pub(crate) struct IpWithZone<A: Borrow<core::net::Ipv6Addr> = core::net::Ipv6Addr> {
pub(crate) ip: A,
pub(crate) zone: Option<core::num::NonZero<u16>>,
}
fn is_unicast_link_local(addr: &core::net::Ipv6Addr) -> bool {
(addr.segments()[0] & 0xffc0) == 0xfe80
}
impl<C, A: Borrow<core::net::Ipv6Addr>> minicbor::encode::Encode<C> for IpWithZone<A> {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
if self.zone.is_none() || !is_unicast_link_local(self.ip.borrow()) {
return encode_as_ip(&self.ip.borrow().octets().as_slice(), e, ctx);
}
let zone = self.zone.map(u16::from).unwrap_or_default(); let e = e.tag(minicbor::data::Tag::new(54))?;
let e = e.array(3)?;
let e = e.bytes(self.ip.borrow().octets().as_slice())?;
let e = e.null()?;
let _ = e.u16(zone.into())?;
Ok(())
}
}
impl<'b, C> minicbor::decode::Decode<'b, C> for IpWithZone {
fn decode(
d: &mut minicbor::decode::Decoder<'b>,
_ctx: &mut C,
) -> Result<Self, minicbor::decode::Error> {
if !d.tag().is_ok_and(|t| t.as_u64() == 54) {
return Err(minicbor::decode::Error::message(
"Expecting tag54 IP address",
));
}
let items = if d.datatype()? == minicbor::data::Type::Array {
match d.array()? {
Some(n) if (1..=3).contains(&n) => n,
_ => {
return Err(minicbor::decode::Error::message(
"Unexpected tag54 array length",
))
}
}
} else {
1
};
let address = d.bytes()?;
let address: [u8; 16] = address
.try_into()
.map_err(|_| minicbor::decode::Error::message("Invalid IP address length"))?;
let mut result = IpWithZone {
ip: core::net::Ipv6Addr::from(address),
zone: None,
};
if items == 1 {
return Ok(result);
}
d.null()?;
if items == 2 {
return Ok(result);
}
let zone = d.u16()?;
result.zone = zone.try_into().ok();
return Ok(result);
}
}
#[inline]
pub(crate) fn encode_as_ip<C, W: minicbor::encode::Write>(
xs: &&[u8],
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
match xs.len() {
4 => e.tag(minicbor::data::Tag::new(52))?,
16 => e.tag(minicbor::data::Tag::new(54))?,
_ => e,
};
minicbor::bytes::encode::<C, &[u8], W>(xs, e, ctx)
}
pub(crate) fn encode_as_mac<C, W: minicbor::encode::Write>(
xs: &&[u8],
e: &mut minicbor::Encoder<W>,
ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.tag(minicbor::data::Tag::new(48))?;
minicbor::bytes::encode::<C, &[u8], W>(xs, e, ctx)
}