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));