blob: 6712d92622f1835c05171f0e4cea949e780fdbd8 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//! Macros used in Netstack3.
/// Implement [`TimerContext`] for one ID type in terms of an existing
/// implementation for a different ID type.
///
/// `$outer_timer_id` is an enum where one variant contains an
/// `$inner_timer_id`. `impl_timer_context!` generates an impl of
/// `TimerContext<$inner_timer_id>` for any `C: TimerContext<$outer_timer_id>`.
///
/// An impl of `Into<$outer_timer_id> for `$inner_timer_id` must exist. `$pat`
/// is a pattern of type `$outer_timer_id` that binds the `$inner_timer_id`.
/// `$bound_variable` is the name of the bound `$inner_timer_id` from the
/// pattern. For example, if `$pat` is `OuterTimerId::Inner(id)`, then
/// `$bound_variable` would be `id`. This is required for macro hygiene.
///
/// If an extra first parameter, `$bound`, is provided, then it is added as an
/// extra bound on the `C` context type.
///
/// [`TimerContext`]: crate::context::TimerContext
macro_rules! impl_timer_context {
($outer_timer_id:ty, $inner_timer_id:ty, $pat:pat, $bound_variable:ident) => {
impl<C: crate::context::TimerContext<$outer_timer_id>>
crate::context::TimerContext<$inner_timer_id> for C
{
impl_timer_context!(@inner $outer_timer_id, $inner_timer_id, $pat, $bound_variable);
}
};
($c_type:ident: $c_bound:ident, $outer_timer_id:ty, $inner_timer_id:ty, $pat:pat, $bound_variable:ident) => {
impl<$c_type: $c_bound + crate::context::TimerContext<$outer_timer_id>>
crate::context::TimerContext<$inner_timer_id> for $c_type
{
impl_timer_context!(@inner $outer_timer_id, $inner_timer_id, $pat, $bound_variable);
}
};
($other_type_arg:ident, $outer_timer_id:ty, $inner_timer_id:ty, $pat:pat, $bound_variable:ident) => {
impl<$other_type_arg, C: crate::context::TimerContext<$outer_timer_id>>
crate::context::TimerContext<$inner_timer_id> for C
{
impl_timer_context!(@inner $outer_timer_id, $inner_timer_id, $pat, $bound_variable);
}
};
($other_type_arg:ident: $o_bound:path, $outer_timer_id:ty, $inner_timer_id:ty, $pat:pat, $bound_variable:ident) => {
impl<$other_type_arg: $o_bound, C: crate::context::TimerContext<$outer_timer_id>>
crate::context::TimerContext<$inner_timer_id> for C
{
impl_timer_context!(@inner $outer_timer_id, $inner_timer_id, $pat, $bound_variable);
}
};
(@inner $outer_timer_id:ty, $inner_timer_id:ty, $pat:pat, $bound_variable:ident) => {
fn schedule_timer_instant(
&mut self,
time: Self::Instant,
id: $inner_timer_id,
) -> Option<Self::Instant> {
crate::context::TimerContext::<$outer_timer_id>::schedule_timer_instant(self, time, id.into())
}
fn cancel_timer(&mut self, id: $inner_timer_id) -> Option<Self::Instant> {
crate::context::TimerContext::<$outer_timer_id>::cancel_timer(self, id.into())
}
fn cancel_timers_with<F: FnMut(&$inner_timer_id) -> bool>(&mut self, mut f: F) {
crate::context::TimerContext::<$outer_timer_id>::cancel_timers_with(self, |id| match id {
$pat => f($bound_variable),
#[allow(unreachable_patterns)]
_ => false,
})
}
fn scheduled_instant(&self, id: $inner_timer_id) -> Option<Self::Instant> {
crate::context::TimerContext::<$outer_timer_id>::scheduled_instant(self, id.into())
}
};
}
/// Declare a benchmark function.
///
/// The function will be named `$name`. If the `benchmark` cfg is enabled, the
/// provided `$fn` will be invoked with a `&mut criterion::Bencher` - in other
/// words, a real benchmark. If the `benchmark` cfg is disabled, the function
/// will be annotated with the `#[test]` attribute, and the provided `$fn` will
/// be invoked with a `&mut TestBencher`, which has the effect of creating a
/// test that runs the benchmarked function for a small, fixed number of
/// iterations. This test allows the use of debug assertions to verify the
/// correctness of the benchmark.
///
/// Note that `$fn` doesn't have to be a named function - it can also be an
/// anonymous closure.
#[cfg(test)]
macro_rules! bench {
($name:ident, $fn:expr) => {
#[cfg(benchmark)]
fn $name(b: &mut criterion::Bencher) {
$fn(b);
}
#[cfg(not(benchmark))]
#[test]
fn $name() {
$fn(&mut crate::testutil::benchmarks::TestBencher);
}
};
}