use scroll::{
ctx::{MeasureWith, TryIntoCtx},
Endian, Pwrite,
};
use super::{Element, RawIEEE80211Element, WrappedIEEE80211Element};
pub trait ChainElement {
type Appended<Appendee>: ChainElement;
fn append<T>(self, value: T) -> Self::Appended<T>;
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
pub struct ElementChainEnd<Inner> {
pub inner: Inner,
}
impl<Inner: Element> ElementChainEnd<Inner> {
#[inline]
pub const fn new(inner: Inner) -> Self {
Self { inner }
}
}
impl<Inner> ChainElement for ElementChainEnd<Inner> {
type Appended<Appendee> = ElementChainLink<Inner, ElementChainEnd<Appendee>>;
#[inline]
fn append<T>(self, value: T) -> Self::Appended<T> {
ElementChainLink {
inner: self.inner,
next: ElementChainEnd { inner: value },
}
}
}
impl<Inner> MeasureWith<()> for ElementChainEnd<Inner>
where
Inner: Element,
{
#[inline]
fn measure_with(&self, ctx: &()) -> usize {
Inner::ELEMENT_ID.element_header_length() + self.inner.measure_with(ctx)
}
}
impl MeasureWith<()> for ElementChainEnd<RawIEEE80211Element<'_>> {
fn measure_with(&self, _ctx: &()) -> usize {
self.inner.slice.len()
}
}
impl<Inner> TryIntoCtx for ElementChainEnd<Inner>
where
Inner: Element,
{
type Error = scroll::Error;
#[inline]
fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
buf.pwrite(WrappedIEEE80211Element(self.inner), 0)
}
}
impl TryIntoCtx for ElementChainEnd<RawIEEE80211Element<'_>> {
type Error = scroll::Error;
fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
buf.pwrite_with(self.inner, 0, Endian::Little)
}
}
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
pub struct ElementChainLink<Inner, Child: ChainElement> {
pub inner: Inner,
pub next: Child,
}
impl<Inner, Child: ChainElement> ChainElement for ElementChainLink<Inner, Child> {
type Appended<Appendee> = ElementChainLink<Inner, <Child as ChainElement>::Appended<Appendee>>;
#[inline]
fn append<T>(self, value: T) -> Self::Appended<T> {
ElementChainLink {
inner: self.inner,
next: self.next.append(value),
}
}
}
impl<Inner, Child> MeasureWith<()> for ElementChainLink<Inner, Child>
where
Inner: Element,
Child: TryIntoCtx<Error = scroll::Error> + MeasureWith<()> + ChainElement,
{
#[inline]
fn measure_with(&self, ctx: &()) -> usize {
Inner::ELEMENT_ID.element_header_length()
+ self.inner.measure_with(ctx)
+ self.next.measure_with(ctx)
}
}
impl<Child> MeasureWith<()> for ElementChainLink<RawIEEE80211Element<'_>, Child>
where
Child: TryIntoCtx<Error = scroll::Error> + MeasureWith<()> + ChainElement,
{
fn measure_with(&self, ctx: &()) -> usize {
self.inner.slice.len() + 2 + self.next.measure_with(ctx)
}
}
impl<Inner, Child> TryIntoCtx for ElementChainLink<Inner, Child>
where
Inner: Element,
Child: TryIntoCtx<Error = scroll::Error> + ChainElement,
{
type Error = scroll::Error;
#[inline]
fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
let mut offset = 0;
buf.gwrite(WrappedIEEE80211Element(self.inner), &mut offset)?;
buf.gwrite(self.next, &mut offset)?;
Ok(offset)
}
}
impl<Child> TryIntoCtx for ElementChainLink<RawIEEE80211Element<'_>, Child>
where
Child: TryIntoCtx<Error = scroll::Error> + ChainElement,
{
type Error = scroll::Error;
fn try_into_ctx(self, buf: &mut [u8], _ctx: ()) -> Result<usize, Self::Error> {
let mut offset = 0;
buf.gwrite_with(self.inner, &mut offset, Endian::Little)?;
buf.gwrite(self.next, &mut offset)?;
Ok(offset)
}
}
#[macro_export]
macro_rules! element_chain {
() => {
$crate::common::Empty
};
($element:expr) => {
{
use $crate::elements::element_chain::ElementChainEnd;
ElementChainEnd {
inner: $element
}
}
};
(
$current_element:expr
$(,$element:expr)+
) => {
{
use ieee80211::elements::element_chain::{ChainElement, ElementChainLink};
ElementChainLink {
inner: $current_element,
next: ::ieee80211::element_chain! ($($element),*)
}
}
};
}