Skip to main content

wlan_hw_sim/event/
extract.rs

1// Copyright 2023 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use fidl_fuchsia_wlan_tap as fidl_tap;
6use std::fmt::{self, Debug, Formatter};
7use std::marker::PhantomData;
8use wlan_common::channel::Channel;
9
10use crate::event::{Handled, Handler};
11
12pub trait FromEvent<E>: Sized {
13    fn from_event(event: &E) -> Option<Self>;
14}
15
16impl FromEvent<fidl_tap::SetChannelArgs> for Channel {
17    fn from_event(event: &fidl_tap::SetChannelArgs) -> Option<Self> {
18        let cbw = wlan_common::channel::Bandwidth::from_fidl(
19            event.bandwidth,
20            event.vht_secondary_80_channel.number,
21        )
22        .ok()?;
23        Some(Channel { primary: event.primary.number, bandwidth: cbw, band: event.primary.band })
24    }
25}
26
27impl FromEvent<fidl_tap::SetCountryArgs> for [u8; 2] {
28    fn from_event(event: &fidl_tap::SetCountryArgs) -> Option<Self> {
29        Some(event.alpha2)
30    }
31}
32
33impl FromEvent<fidl_tap::TxArgs> for fidl_tap::WlanTxPacket {
34    fn from_event(event: &fidl_tap::TxArgs) -> Option<Self> {
35        Some(event.packet.clone())
36    }
37}
38
39/// An event handler that is implemented over combinations of adapters and arbitrary function
40/// parameters that are extracted from the given event.
41#[repr(transparent)]
42pub struct Extract<X, F> {
43    f: F,
44    phantom: PhantomData<fn() -> X>,
45}
46
47impl<X, F> Extract<X, F> {
48    fn new(f: F) -> Self {
49        Extract { f, phantom: PhantomData }
50    }
51}
52
53impl<X, F> Clone for Extract<X, F>
54where
55    F: Clone,
56{
57    fn clone(&self) -> Self {
58        Extract { f: self.f.clone(), phantom: PhantomData }
59    }
60}
61
62impl<X, F> Debug for Extract<X, F> {
63    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
64        f.debug_struct("Extract").field("f", &"{unknown}").finish()
65    }
66}
67
68impl<X, F> Copy for Extract<X, F> where F: Copy {}
69
70// Unless adapted, handlers normally return a `Handled` that indicates whether or not they have
71// matched a given event. However, extractors default to the more common case and match if
72// extraction is successful (the composed function does **not** return a `Handled`). For the less
73// common case where the matching predicate is more complex, the `extract_and_match` function must
74// be used.
75#[derive(Clone, Copy, Debug)]
76#[repr(transparent)]
77pub struct AndMatch<E>(pub E);
78
79// Unless adapted, handlers normally receive state. However, extractors (and most handlers) rarely
80// need state. Because extractors take the form of functions with various parameters, they default
81// to the more common case and ignore state unless this marker type is used.
82/// A marker type that indicates that an extractor's first parameter accepts handler state.
83///
84/// When using state, the type of the state must be fully qualified and cannot be inferred. For
85/// more complex state types, consider using a type definition.
86///
87/// # Examples
88///
89/// This type must be used to interact with handler state within an extractor. The following
90/// constructs an event handler that runs and matches when a management frame can be extracted from
91/// an event and has exclusive access to state when it runs.
92///
93/// ```rust,ignore
94/// let mut handler = event::extract(Stateful(|state: &mut State, frame: Buffered<MgmtFrame>| {
95///     /* ... */
96/// }));
97/// ```
98#[derive(Clone, Copy, Debug)]
99#[repr(transparent)]
100pub struct Stateful<F>(pub F);
101
102/// Constructs an extractor event handler that runs and matches when its parameters can be
103/// extracted from an event.
104///
105/// An extractor executes when the arguments of its composed function can be constructed from an
106/// event. This both routes events within an event handler and extracts the necessary data for a
107/// handler declaratively without the need for the handler to destructure, convert, nor reference
108/// data in an ad-hoc manner.
109///
110/// # Examples
111///
112/// The following constructs an event handler that runs and matches when an authentication
113/// management frame can be extracted from a transmission event.
114///
115/// ```rust,ignore
116/// let mut handler = event::on_transmit(event::extract(|frame: Buffered<AuthFrame>| {
117///     let frame = frame.get();
118///     assert_eq!(
119///         { frame.auth_hdr.status_code },
120///         StatusCode::Success.into(),
121///     );
122/// }));
123/// ```
124pub fn extract<S, E, Z, F>(
125    f: F,
126) -> impl Handler<S, E, Output = <Extract<Z, F> as Handler<S, E>>::Output>
127where
128    Extract<Z, F>: Handler<S, E>,
129{
130    let mut extract = Extract::new(f);
131    move |state: &mut S, event: &E| extract.call(state, event)
132}
133
134/// Constructs an extractor event handler that runs when its parameters can be extracted from an
135/// event.
136///
137/// This function behaves much like [`extract`], but its composed function must return a
138/// [`Handled`] and the constructed event handler does not match unless the extraction is
139/// successful **and** the composed function indicates a match.
140///
141/// # Examples
142///
143/// The following constructs an event handler that runs when a management frame can be extracted
144/// from a transmission event and only matches when the management frame subtype is supported.
145/// (Note that this differs from extracting `Buffered<Supported<MgmtFrame>>`, as this handler
146/// executes for any management frame while that handler would only execute if the frame is
147/// supported.)
148///
149/// ```rust,ignore
150/// use Handled::{Matched, Unmatched};
151///
152/// let mut handler = event::on_transmit(event::extract_and_match(|frame: Buffered<MgmtFrame>| {
153///     let frame = frame.get();
154///     // ...
155///     if MgmtFrame::tag(frame).is_supported() { Matched(()) } else { Unmatched }
156/// }));
157/// ```
158///
159/// [`extract`]: crate::event::extract
160/// [`Handled`]: crate::event::Handled
161pub fn extract_and_match<S, E, Z, F>(
162    f: F,
163) -> impl Handler<S, E, Output = <AndMatch<Extract<Z, F>> as Handler<S, E>>::Output>
164where
165    AndMatch<Extract<Z, F>>: Handler<S, E>,
166{
167    let mut extract = AndMatch(Extract::new(f));
168    move |state: &mut S, event: &E| extract.call(state, event)
169}
170
171// Invokes another macro with the subsequences of a single tuple parameter (down to a unary tuple).
172// That is, given a macro `f` and the starting tuple `(T1, T2)`, this macro invokes `f!((T1, T2))`
173// and `f!((T2,))`.
174macro_rules! with_tuples {
175    ($f:ident$(,)?) => {};
176    ($f:ident, ( $head:ident$(,)? )$(,)?) => {
177        $f!(($head));
178        with_tuples!($f);
179    };
180    ($f:ident, ( $head:ident,$($tail:ident),* $(,)? )$(,)?) => {
181        $f!(($head,$($tail,)*));
182        with_tuples!($f, ($($tail,)*));
183    };
184}
185// Implements the `Handler` trait for `Extract` and related types in this module. Matching
186// parameters is accomplished via implementations over tuples of the parameter types. Each type
187// must implement `FromEvent` and `from_event` is called against the event and forwarded to the
188// parameters of the function.
189macro_rules! impl_handler_for_extract {
190    (( $($t:ident),* $(,)?)$(,)?) => {
191        #[allow(non_snake_case)]
192        impl<S, E, T, F, $($t,)*> Handler<S, E> for Extract<($($t,)*), F>
193        where
194            F: FnMut($($t,)*) -> T,
195            $(
196                $t: FromEvent<E>,
197            )*
198        {
199            type Output = T;
200
201            fn call(&mut self, _state: &mut S, event: &E) -> Handled<Self::Output> {
202                match (move || {
203                    Some(($(
204                        $t::from_event(event)?,
205                    )*))
206                })() {
207                    Some(($($t,)*)) => Handled::Matched((self.f)($($t,)*)),
208                    _ => Handled::Unmatched,
209                }
210            }
211        }
212
213        #[allow(non_snake_case)]
214        impl<S, E, T, F, $($t,)*> Handler<S, E> for Extract<Stateful<($($t,)*)>, Stateful<F>>
215        where
216            F: FnMut(&mut S, $($t,)*) -> T,
217            $(
218                $t: FromEvent<E>,
219            )*
220        {
221            type Output = T;
222
223            fn call(&mut self, state: &mut S, event: &E) -> Handled<Self::Output> {
224                match (move || {
225                    Some(($(
226                        $t::from_event(event)?,
227                    )*))
228                })() {
229                    Some(($($t,)*)) => Handled::Matched((self.f.0)(state, $($t,)*)),
230                    _ => Handled::Unmatched,
231                }
232            }
233        }
234        #[allow(non_snake_case)]
235        impl<S, E, T, F, $($t,)*> Handler<S, E> for AndMatch<Extract<($($t,)*), F>>
236        where
237            F: FnMut($($t,)*) -> Handled<T>,
238            $(
239                $t: FromEvent<E>,
240            )*
241        {
242            type Output = T;
243
244            fn call(&mut self, _state: &mut S, event: &E) -> Handled<Self::Output> {
245                match (move || {
246                    Some(($(
247                        $t::from_event(event)?,
248                    )*))
249                })() {
250                    Some(($($t,)*)) => (self.0.f)($($t,)*),
251                    _ => Handled::Unmatched,
252                }
253            }
254        }
255
256        #[allow(non_snake_case)]
257        impl<S, E, T, F, $($t,)*> Handler<S, E> for AndMatch<
258            Extract<Stateful<($($t,)*)>, Stateful<F>>
259        >
260        where
261            F: FnMut(&mut S, $($t,)*) -> Handled<T>,
262            $(
263                $t: FromEvent<E>,
264            )*
265        {
266            type Output = T;
267
268            fn call(&mut self, state: &mut S, event: &E) -> Handled<Self::Output> {
269                match (move || {
270                    Some(($(
271                        $t::from_event(event)?,
272                    )*))
273                })() {
274                    Some(($($t,)*)) => (self.0.f.0)(state, $($t,)*),
275                    _ => Handled::Unmatched,
276                }
277            }
278        }
279    };
280}
281with_tuples!(impl_handler_for_extract, (T1, T2, T3, T4, T5, T6));