1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
// Copyright 2024 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.

//! A shareable fake bindings context.

use alloc::vec::Vec;
use core::{convert::Infallible as Never, fmt::Debug};

use crate::{
    sync::DynDebugReferences,
    testutil::{
        FakeCryptoRng, FakeEventCtx, FakeFrameCtx, FakeInstantCtx, FakeTimerCtx,
        WithFakeTimerContext,
    },
    ContextProvider, DeferredResourceRemovalContext, EventContext, ReferenceNotifiers, RngContext,
    TimerBindingsTypes, TimerContext, TracingContext,
};

/// A test helper used to provide an implementation of a bindings context.
pub struct FakeBindingsCtx<TimerId, Event: Debug, State, FrameMeta> {
    /// Provides [`RngContext`].
    pub rng: FakeCryptoRng,
    /// Provides [`TimerContext`].
    pub timers: FakeTimerCtx<TimerId>,
    /// Provides [`EventContext`].
    pub events: FakeEventCtx<Event>,
    /// Provides [`SendFrameContext`].
    pub frames: FakeFrameCtx<FrameMeta>,
    /// Generic state used by specific tests.
    pub state: State,
}

impl<TimerId, Event: Debug, State, FrameMeta> ContextProvider
    for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
{
    type Context = Self;
    fn context(&mut self) -> &mut Self::Context {
        self
    }
}

impl<TimerId, Event: Debug, State: Default, FrameMeta> Default
    for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
{
    fn default() -> Self {
        Self {
            rng: FakeCryptoRng::new_xorshift(0),
            timers: FakeTimerCtx::default(),
            events: FakeEventCtx::default(),
            frames: FakeFrameCtx::default(),
            state: Default::default(),
        }
    }
}

impl<TimerId, Event: Debug, State, FrameMeta> FakeBindingsCtx<TimerId, Event, State, FrameMeta> {
    /// Seed the testing RNG with a specific value.
    pub fn seed_rng(&mut self, seed: u128) {
        self.rng = FakeCryptoRng::new_xorshift(seed);
    }

    /// Takes all the accumulated events from the [`FakeEventCtx`].
    pub fn take_events(&mut self) -> Vec<Event> {
        self.events.take()
    }
}

impl<TimerId, Event: Debug, State, FrameMeta> RngContext
    for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
{
    type Rng<'a> = FakeCryptoRng where Self: 'a;

    fn rng(&mut self) -> Self::Rng<'_> {
        self.rng.clone()
    }
}

impl<Id, Event: Debug, State, FrameMeta> AsRef<FakeInstantCtx>
    for FakeBindingsCtx<Id, Event, State, FrameMeta>
{
    fn as_ref(&self) -> &FakeInstantCtx {
        self.timers.as_ref()
    }
}

impl<Id, Event: Debug, State, FrameMeta> AsRef<FakeTimerCtx<Id>>
    for FakeBindingsCtx<Id, Event, State, FrameMeta>
{
    fn as_ref(&self) -> &FakeTimerCtx<Id> {
        &self.timers
    }
}

impl<Id, Event: Debug, State, FrameMeta> AsMut<FakeTimerCtx<Id>>
    for FakeBindingsCtx<Id, Event, State, FrameMeta>
{
    fn as_mut(&mut self) -> &mut FakeTimerCtx<Id> {
        &mut self.timers
    }
}

impl<Id: Debug + PartialEq + Clone + Send + Sync, Event: Debug, State, FrameMeta> TimerBindingsTypes
    for FakeBindingsCtx<Id, Event, State, FrameMeta>
{
    type Timer = <FakeTimerCtx<Id> as TimerBindingsTypes>::Timer;
    type DispatchId = <FakeTimerCtx<Id> as TimerBindingsTypes>::DispatchId;
}

impl<Id: Debug + PartialEq + Clone + Send + Sync, Event: Debug, State, FrameMeta> TimerContext
    for FakeBindingsCtx<Id, Event, State, FrameMeta>
{
    fn new_timer(&mut self, id: Self::DispatchId) -> Self::Timer {
        self.timers.new_timer(id)
    }

    fn schedule_timer_instant(
        &mut self,
        time: Self::Instant,
        timer: &mut Self::Timer,
    ) -> Option<Self::Instant> {
        self.timers.schedule_timer_instant(time, timer)
    }

    fn cancel_timer(&mut self, timer: &mut Self::Timer) -> Option<Self::Instant> {
        self.timers.cancel_timer(timer)
    }

    fn scheduled_instant(&self, timer: &mut Self::Timer) -> Option<Self::Instant> {
        self.timers.scheduled_instant(timer)
    }
}

impl<Id, Event: Debug, State, FrameMeta> EventContext<Event>
    for FakeBindingsCtx<Id, Event, State, FrameMeta>
{
    fn on_event(&mut self, event: Event) {
        self.events.on_event(event)
    }
}

impl<Id, Event: Debug, State, FrameMeta> TracingContext
    for FakeBindingsCtx<Id, Event, State, FrameMeta>
{
    type DurationScope = ();

    fn duration(&self, _: &'static core::ffi::CStr) {}
}

impl<Id, Event: Debug, State, FrameMeta> ReferenceNotifiers
    for FakeBindingsCtx<Id, Event, State, FrameMeta>
{
    type ReferenceReceiver<T: 'static> = Never;

    type ReferenceNotifier<T: Send + 'static> = Never;

    fn new_reference_notifier<T: Send + 'static>(
        debug_references: DynDebugReferences,
    ) -> (Self::ReferenceNotifier<T>, Self::ReferenceReceiver<T>) {
        // NB: We don't want deferred destruction in core tests. These are
        // always single-threaded and single-task, and we want to encourage
        // explicit cleanup.
        panic!(
            "FakeBindingsCtx can't create deferred reference notifiers for type {}: \
            debug_references={debug_references:?}",
            core::any::type_name::<T>()
        );
    }
}

impl<Id, Event: Debug, State, FrameMeta> DeferredResourceRemovalContext
    for FakeBindingsCtx<Id, Event, State, FrameMeta>
{
    fn defer_removal<T: Send + 'static>(&mut self, receiver: Self::ReferenceReceiver<T>) {
        match receiver {}
    }
}

impl<TimerId, Event: Debug, State, FrameMeta> WithFakeTimerContext<TimerId>
    for FakeBindingsCtx<TimerId, Event, State, FrameMeta>
{
    fn with_fake_timer_ctx<O, F: FnOnce(&FakeTimerCtx<TimerId>) -> O>(&self, f: F) -> O {
        f(&self.timers)
    }

    fn with_fake_timer_ctx_mut<O, F: FnOnce(&mut FakeTimerCtx<TimerId>) -> O>(
        &mut self,
        f: F,
    ) -> O {
        f(&mut self.timers)
    }
}