1use core::convert::Infallible;
9use std::{
10 cell::{Cell, RefCell},
11 collections::VecDeque,
12 rc::Rc,
13 vec::Vec,
14};
15
16use core::task::{Context, Poll};
17use embedded_hal_async::delay::DelayNs;
18use rand::{Rng, TryCryptoRng, TryRng};
19use umsh_core::PublicKey;
20use umsh_crypto::{
21 AesCipher, AesProvider, CryptoEngine, NodeIdentity, Sha256Provider, SharedSecret,
22};
23use umsh_hal::{Clock, CounterStore, KeyValueStore, Radio, RxInfo, Snr, TxError, TxOptions};
24
25use crate::{
26 DEFAULT_ACKS, DEFAULT_CHANNELS, DEFAULT_DUP, DEFAULT_FRAME, DEFAULT_IDENTITIES, DEFAULT_PEERS,
27 DEFAULT_TX, Mac, OperatingPolicy, Platform, RepeaterConfig,
28};
29
30const DEFAULT_RSSI: i16 = -40;
31const DEFAULT_SNR: Snr = Snr::from_decibels(10);
32
33pub type TestMac<
35 const IDENTITIES: usize = DEFAULT_IDENTITIES,
36 const PEERS: usize = DEFAULT_PEERS,
37 const CHANNELS: usize = DEFAULT_CHANNELS,
38 const ACKS: usize = DEFAULT_ACKS,
39 const TX: usize = DEFAULT_TX,
40 const FRAME: usize = DEFAULT_FRAME,
41 const DUP: usize = DEFAULT_DUP,
42> = Mac<TestPlatform, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP>;
43
44pub type ModeledTestMac<
46 const IDENTITIES: usize = DEFAULT_IDENTITIES,
47 const PEERS: usize = DEFAULT_PEERS,
48 const CHANNELS: usize = DEFAULT_CHANNELS,
49 const ACKS: usize = DEFAULT_ACKS,
50 const TX: usize = DEFAULT_TX,
51 const FRAME: usize = DEFAULT_FRAME,
52 const DUP: usize = DEFAULT_DUP,
53> = Mac<ModeledTestPlatform, IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP>;
54
55pub struct TestPlatform;
57
58impl Platform for TestPlatform {
59 type Identity = DummyIdentity;
60 type Aes = DummyAes;
61 type Sha = DummySha;
62 type Radio = SimulatedRadio;
63 type Delay = DummyDelay;
64 type Clock = DummyClock;
65 type Rng = DummyRng;
66 type CounterStore = DummyCounterStore;
67 type KeyValueStore = DummyKeyValueStore;
68}
69
70pub struct ModeledTestPlatform;
72
73impl Platform for ModeledTestPlatform {
74 type Identity = DummyIdentity;
75 type Aes = DummyAes;
76 type Sha = DummySha;
77 type Radio = ModeledRadio;
78 type Delay = DummyDelay;
79 type Clock = DummyClock;
80 type Rng = DummyRng;
81 type CounterStore = DummyCounterStore;
82 type KeyValueStore = DummyKeyValueStore;
83}
84
85pub fn make_test_mac<
87 const IDENTITIES: usize,
88 const PEERS: usize,
89 const CHANNELS: usize,
90 const ACKS: usize,
91 const TX: usize,
92 const FRAME: usize,
93 const DUP: usize,
94>(
95 radio: SimulatedRadio,
96 clock: DummyClock,
97) -> TestMac<IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP> {
98 Mac::new(
99 radio,
100 CryptoEngine::new(DummyAes, DummySha),
101 clock,
102 DummyRng::default(),
103 DummyCounterStore,
104 RepeaterConfig::default(),
105 OperatingPolicy::default(),
106 )
107}
108
109pub fn make_modeled_test_mac<
111 const IDENTITIES: usize,
112 const PEERS: usize,
113 const CHANNELS: usize,
114 const ACKS: usize,
115 const TX: usize,
116 const FRAME: usize,
117 const DUP: usize,
118>(
119 radio: ModeledRadio,
120 clock: DummyClock,
121) -> ModeledTestMac<IDENTITIES, PEERS, CHANNELS, ACKS, TX, FRAME, DUP> {
122 Mac::new(
123 radio,
124 CryptoEngine::new(DummyAes, DummySha),
125 clock,
126 DummyRng::default(),
127 DummyCounterStore,
128 RepeaterConfig::default(),
129 OperatingPolicy::default(),
130 )
131}
132
133#[derive(Clone)]
135pub struct SimulatedNetwork {
136 inner: Rc<RefCell<NetworkState>>,
137}
138
139struct NetworkState {
140 inboxes: Vec<VecDeque<QueuedFrame>>,
141 links: Vec<Vec<LinkProfile>>,
142}
143
144struct QueuedFrame {
145 data: Vec<u8>,
146 rssi: i16,
147 snr: Snr,
148}
149
150#[derive(Clone, Copy)]
151struct LinkProfile {
152 connected: bool,
153 rssi: i16,
154 snr: Snr,
155}
156
157impl Default for LinkProfile {
158 fn default() -> Self {
159 Self {
160 connected: false,
161 rssi: DEFAULT_RSSI,
162 snr: DEFAULT_SNR,
163 }
164 }
165}
166
167impl Default for SimulatedNetwork {
168 fn default() -> Self {
169 Self::new()
170 }
171}
172
173impl SimulatedNetwork {
174 pub fn new() -> Self {
176 Self {
177 inner: Rc::new(RefCell::new(NetworkState {
178 inboxes: Vec::new(),
179 links: Vec::new(),
180 })),
181 }
182 }
183
184 pub fn add_radio(&self) -> SimulatedRadio {
186 self.add_radio_with_config(256, 10)
187 }
188
189 pub fn add_radio_with_config(&self, max_frame_size: usize, t_frame_ms: u32) -> SimulatedRadio {
191 let mut state = self.inner.borrow_mut();
192 let id = state.inboxes.len();
193 for row in &mut state.links {
194 row.push(LinkProfile::default());
195 }
196 state.inboxes.push(VecDeque::new());
197 state.links.push(vec![LinkProfile::default(); id + 1]);
198 SimulatedRadio {
199 network: self.clone(),
200 id,
201 max_frame_size,
202 t_frame_ms,
203 }
204 }
205
206 pub fn connect(&self, from: usize, to: usize) {
208 self.set_link(from, to, true, DEFAULT_RSSI, DEFAULT_SNR);
209 }
210
211 pub fn connect_bidirectional(&self, a: usize, b: usize) {
213 self.connect(a, b);
214 self.connect(b, a);
215 }
216
217 pub fn disconnect(&self, from: usize, to: usize) {
219 self.set_link(from, to, false, DEFAULT_RSSI, DEFAULT_SNR);
220 }
221
222 pub fn set_link(&self, from: usize, to: usize, connected: bool, rssi: i16, snr: Snr) {
224 let mut state = self.inner.borrow_mut();
225 let Some(row) = state.links.get_mut(from) else {
226 panic!("unknown simulated radio id {from}");
227 };
228 let Some(link) = row.get_mut(to) else {
229 panic!("unknown simulated radio id {to}");
230 };
231 *link = LinkProfile {
232 connected,
233 rssi,
234 snr,
235 };
236 }
237
238 pub fn inject_frame(&self, to: usize, frame: &[u8]) {
240 self.inject_frame_with_info(to, frame, DEFAULT_RSSI, DEFAULT_SNR);
241 }
242
243 pub fn inject_frame_with_info(&self, to: usize, frame: &[u8], rssi: i16, snr: Snr) {
245 let mut state = self.inner.borrow_mut();
246 let Some(queue) = state.inboxes.get_mut(to) else {
247 panic!("unknown simulated radio id {to}");
248 };
249 queue.push_back(QueuedFrame {
250 data: frame.to_vec(),
251 rssi,
252 snr,
253 });
254 }
255
256 fn transmit(&self, from: usize, frame: &[u8]) {
257 let mut state = self.inner.borrow_mut();
258 let Some(row) = state.links.get(from) else {
259 panic!("unknown simulated radio id {from}");
260 };
261 let deliveries: Vec<(usize, i16, Snr)> = row
262 .iter()
263 .enumerate()
264 .filter_map(|(to, link)| link.connected.then_some((to, link.rssi, link.snr)))
265 .collect();
266 for (to, rssi, snr) in deliveries {
267 state.inboxes[to].push_back(QueuedFrame {
268 data: frame.to_vec(),
269 rssi,
270 snr,
271 });
272 }
273 }
274
275 fn receive(&self, id: usize, buf: &mut [u8]) -> RxInfo {
276 let mut state = self.inner.borrow_mut();
277 let Some(queue) = state.inboxes.get_mut(id) else {
278 panic!("unknown simulated radio id {id}");
279 };
280 let Some(frame) = queue.pop_front() else {
281 return RxInfo {
282 len: 0,
283 rssi: 0,
284 snr: Snr::from_decibels(0),
285 lqi: None,
286 };
287 };
288 let len = frame.data.len().min(buf.len());
289 buf[..len].copy_from_slice(&frame.data[..len]);
290 RxInfo {
291 len,
292 rssi: frame.rssi,
293 snr: frame.snr,
294 lqi: None,
295 }
296 }
297}
298
299#[derive(Clone)]
301pub struct SimulatedRadio {
302 network: SimulatedNetwork,
303 id: usize,
304 max_frame_size: usize,
305 t_frame_ms: u32,
306}
307
308impl SimulatedRadio {
309 pub fn id(&self) -> usize {
311 self.id
312 }
313}
314
315impl Radio for SimulatedRadio {
316 type Error = ();
317
318 async fn transmit(
319 &mut self,
320 data: &[u8],
321 _options: TxOptions,
322 ) -> Result<(), TxError<Self::Error>> {
323 self.network.transmit(self.id, data);
324 Ok(())
325 }
326
327 fn poll_receive(
328 &mut self,
329 _cx: &mut Context<'_>,
330 buf: &mut [u8],
331 ) -> Poll<Result<RxInfo, Self::Error>> {
332 let rx = self.network.receive(self.id, buf);
333 if rx.len == 0 {
334 Poll::Pending
335 } else {
336 Poll::Ready(Ok(rx))
337 }
338 }
339
340 fn max_frame_size(&self) -> usize {
341 self.max_frame_size
342 }
343
344 fn t_frame_ms(&self) -> u32 {
345 self.t_frame_ms
346 }
347}
348
349#[derive(Clone, Copy, Debug, PartialEq, Eq)]
351pub struct ModeledLinkProfile {
352 pub connected: bool,
353 pub base_rssi: i16,
354 pub base_snr: Snr,
355 pub rssi_jitter_dbm: i16,
356 pub snr_jitter_centibels: i16,
357 pub propagation_delay_ms: u32,
358 pub drop_per_thousand: u16,
359}
360
361impl Default for ModeledLinkProfile {
362 fn default() -> Self {
363 Self {
364 connected: false,
365 base_rssi: DEFAULT_RSSI,
366 base_snr: DEFAULT_SNR,
367 rssi_jitter_dbm: 2,
368 snr_jitter_centibels: 10,
369 propagation_delay_ms: 0,
370 drop_per_thousand: 0,
371 }
372 }
373}
374
375impl ModeledLinkProfile {
376 pub fn connected() -> Self {
378 Self {
379 connected: true,
380 ..Self::default()
381 }
382 }
383}
384
385#[derive(Clone)]
387pub struct ModeledNetwork {
388 inner: Rc<RefCell<ModeledNetworkState>>,
389 clock: DummyClock,
390}
391
392struct ModeledNetworkState {
393 inboxes: Vec<VecDeque<QueuedFrame>>,
394 links: Vec<Vec<ModeledLinkProfile>>,
395 in_flight: Vec<InFlightTransmission>,
396 scheduled: Vec<ScheduledDelivery>,
397 rng: ModeledRng,
398}
399
400struct InFlightTransmission {
401 from: usize,
402 start_ms: u64,
403 end_ms: u64,
404}
405
406struct ScheduledDelivery {
407 to: usize,
408 available_at_ms: u64,
409 start_ms: u64,
410 end_ms: u64,
411 data: Vec<u8>,
412 rssi: i16,
413 snr: Snr,
414 collided: bool,
415}
416
417impl ModeledNetwork {
418 pub fn new() -> Self {
420 Self::with_clock(DummyClock::new(0))
421 }
422
423 pub fn with_clock(clock: DummyClock) -> Self {
425 Self {
426 inner: Rc::new(RefCell::new(ModeledNetworkState {
427 inboxes: Vec::new(),
428 links: Vec::new(),
429 in_flight: Vec::new(),
430 scheduled: Vec::new(),
431 rng: ModeledRng::new(0x554d_5348),
432 })),
433 clock,
434 }
435 }
436
437 pub fn clock(&self) -> DummyClock {
439 self.clock.clone()
440 }
441
442 pub fn advance_ms(&self, delta_ms: u64) {
444 self.clock.advance_ms(delta_ms);
445 self.promote_due_frames();
446 }
447
448 pub fn reseed(&self, seed: u64) {
450 self.inner.borrow_mut().rng = ModeledRng::new(seed);
451 }
452
453 pub fn add_radio(&self) -> ModeledRadio {
455 self.add_radio_with_config(256, 100)
456 }
457
458 pub fn add_radio_with_config(&self, max_frame_size: usize, t_frame_ms: u32) -> ModeledRadio {
460 let mut state = self.inner.borrow_mut();
461 let id = state.inboxes.len();
462 for row in &mut state.links {
463 row.push(ModeledLinkProfile::default());
464 }
465 state.inboxes.push(VecDeque::new());
466 state
467 .links
468 .push(vec![ModeledLinkProfile::default(); id + 1]);
469 ModeledRadio {
470 network: self.clone(),
471 id,
472 max_frame_size,
473 t_frame_ms,
474 }
475 }
476
477 pub fn connect(&self, from: usize, to: usize) {
479 self.set_link_profile(from, to, ModeledLinkProfile::connected());
480 }
481
482 pub fn connect_bidirectional(&self, a: usize, b: usize) {
484 self.connect(a, b);
485 self.connect(b, a);
486 }
487
488 pub fn disconnect(&self, from: usize, to: usize) {
490 self.set_link_profile(from, to, ModeledLinkProfile::default());
491 }
492
493 pub fn set_link_profile(&self, from: usize, to: usize, profile: ModeledLinkProfile) {
495 let mut state = self.inner.borrow_mut();
496 let Some(row) = state.links.get_mut(from) else {
497 panic!("unknown modeled radio id {from}");
498 };
499 let Some(link) = row.get_mut(to) else {
500 panic!("unknown modeled radio id {to}");
501 };
502 *link = profile;
503 }
504
505 pub fn has_pending_deliveries(&self) -> bool {
507 !self.inner.borrow().scheduled.is_empty()
508 }
509
510 fn promote_due_frames(&self) {
511 let now_ms = self.clock.now_ms();
512 let mut state = self.inner.borrow_mut();
513 state.in_flight.retain(|tx| tx.end_ms > now_ms);
514 let mut index = 0usize;
515 while index < state.scheduled.len() {
516 if state.scheduled[index].available_at_ms > now_ms {
517 index += 1;
518 continue;
519 }
520 let delivery = state.scheduled.swap_remove(index);
521 if delivery.collided {
522 continue;
523 }
524 state.inboxes[delivery.to].push_back(QueuedFrame {
525 data: delivery.data,
526 rssi: delivery.rssi,
527 snr: delivery.snr,
528 });
529 }
530 }
531
532 fn channel_busy(&self, from: usize, now_ms: u64) -> bool {
533 let state = self.inner.borrow();
534 state.in_flight.iter().any(|tx| {
535 tx.from != from
536 && tx.start_ms <= now_ms
537 && now_ms < tx.end_ms
538 && state
539 .links
540 .get(tx.from)
541 .and_then(|row| row.get(from))
542 .map(|profile| profile.connected)
543 .unwrap_or(false)
544 })
545 }
546
547 fn transmit(
548 &self,
549 from: usize,
550 frame: &[u8],
551 t_frame_ms: u32,
552 options: TxOptions,
553 ) -> Result<(), TxError<()>> {
554 self.promote_due_frames();
555 let now_ms = self.clock.now_ms();
556 if options.cad_timeout_ms.is_some() && self.channel_busy(from, now_ms) {
557 return Err(TxError::CadTimeout);
558 }
559
560 let mut state = self.inner.borrow_mut();
561 let Some(row) = state.links.get(from) else {
562 panic!("unknown modeled radio id {from}");
563 };
564 let start_ms = now_ms;
565 let end_ms = now_ms.saturating_add(u64::from(t_frame_ms));
566 let deliveries: Vec<(usize, ModeledLinkProfile)> = row
567 .iter()
568 .enumerate()
569 .filter_map(|(to, link)| link.connected.then_some((to, *link)))
570 .collect();
571
572 for (to, profile) in deliveries {
573 if profile.drop_per_thousand > 0
574 && state.rng.random_u16(1000) < profile.drop_per_thousand
575 {
576 continue;
577 }
578
579 let rssi_jitter = if profile.rssi_jitter_dbm > 0 {
580 state
581 .rng
582 .random_i16_inclusive(-profile.rssi_jitter_dbm, profile.rssi_jitter_dbm)
583 } else {
584 0
585 };
586 let snr_jitter = if profile.snr_jitter_centibels > 0 {
587 state.rng.random_i16_inclusive(
588 -profile.snr_jitter_centibels,
589 profile.snr_jitter_centibels,
590 )
591 } else {
592 0
593 };
594 let propagation_delay_ms = u64::from(profile.propagation_delay_ms);
595 let available_at_ms = end_ms.saturating_add(propagation_delay_ms);
596 let mut delivery = ScheduledDelivery {
597 to,
598 available_at_ms,
599 start_ms,
600 end_ms,
601 data: frame.to_vec(),
602 rssi: profile.base_rssi.saturating_add(rssi_jitter),
603 snr: Snr::from_centibels(
604 profile.base_snr.as_centibels().saturating_add(snr_jitter),
605 ),
606 collided: false,
607 };
608
609 for existing in &mut state.scheduled {
610 if existing.to != to {
611 continue;
612 }
613 if existing.start_ms < end_ms && start_ms < existing.end_ms {
614 existing.collided = true;
615 delivery.collided = true;
616 }
617 }
618
619 state.scheduled.push(delivery);
620 }
621
622 state.in_flight.push(InFlightTransmission {
623 from,
624 start_ms,
625 end_ms,
626 });
627 Ok(())
628 }
629
630 fn receive(&self, id: usize, buf: &mut [u8]) -> RxInfo {
631 self.promote_due_frames();
632 let mut state = self.inner.borrow_mut();
633 let Some(queue) = state.inboxes.get_mut(id) else {
634 panic!("unknown modeled radio id {id}");
635 };
636 let Some(frame) = queue.pop_front() else {
637 return RxInfo {
638 len: 0,
639 rssi: 0,
640 snr: Snr::from_decibels(0),
641 lqi: None,
642 };
643 };
644 let len = frame.data.len().min(buf.len());
645 buf[..len].copy_from_slice(&frame.data[..len]);
646 RxInfo {
647 len,
648 rssi: frame.rssi,
649 snr: frame.snr,
650 lqi: None,
651 }
652 }
653}
654
655impl Default for ModeledNetwork {
656 fn default() -> Self {
657 Self::new()
658 }
659}
660
661#[derive(Clone)]
663pub struct ModeledRadio {
664 network: ModeledNetwork,
665 id: usize,
666 max_frame_size: usize,
667 t_frame_ms: u32,
668}
669
670#[derive(Clone, Copy)]
671struct ModeledRng(u64);
672
673impl ModeledRng {
674 fn new(seed: u64) -> Self {
675 Self(seed.max(1))
676 }
677
678 fn next_u32(&mut self) -> u32 {
679 let mut x = self.0;
680 x ^= x << 13;
681 x ^= x >> 7;
682 x ^= x << 17;
683 self.0 = x.max(1);
684 x as u32
685 }
686
687 fn random_u16(&mut self, upper_exclusive: u16) -> u16 {
688 if upper_exclusive == 0 {
689 0
690 } else {
691 (self.next_u32() % u32::from(upper_exclusive)) as u16
692 }
693 }
694
695 fn random_i16_inclusive(&mut self, min: i16, max: i16) -> i16 {
696 if min >= max {
697 min
698 } else {
699 let span = (i32::from(max) - i32::from(min) + 1) as u32;
700 (i32::from(min) + (self.next_u32() % span) as i32) as i16
701 }
702 }
703}
704
705impl ModeledRadio {
706 pub fn id(&self) -> usize {
708 self.id
709 }
710}
711
712impl Radio for ModeledRadio {
713 type Error = ();
714
715 async fn transmit(
716 &mut self,
717 data: &[u8],
718 options: TxOptions,
719 ) -> Result<(), TxError<Self::Error>> {
720 self.network
721 .transmit(self.id, data, self.t_frame_ms, options)
722 }
723
724 fn poll_receive(
725 &mut self,
726 _cx: &mut Context<'_>,
727 buf: &mut [u8],
728 ) -> Poll<Result<RxInfo, Self::Error>> {
729 let rx = self.network.receive(self.id, buf);
730 if rx.len == 0 {
731 Poll::Pending
732 } else {
733 Poll::Ready(Ok(rx))
734 }
735 }
736
737 fn max_frame_size(&self) -> usize {
738 self.max_frame_size
739 }
740
741 fn t_frame_ms(&self) -> u32 {
742 self.t_frame_ms
743 }
744}
745
746#[derive(Clone)]
750pub struct DummyIdentity {
751 public_key: PublicKey,
752}
753
754impl DummyIdentity {
755 pub fn new(bytes: [u8; 32]) -> Self {
757 Self {
758 public_key: PublicKey(bytes),
759 }
760 }
761}
762
763impl NodeIdentity for DummyIdentity {
764 type Error = ();
765
766 fn public_key(&self) -> &PublicKey {
767 &self.public_key
768 }
769
770 async fn sign(&self, _message: &[u8]) -> Result<[u8; 64], Self::Error> {
771 Ok([0u8; 64])
772 }
773
774 async fn agree(&self, peer: &PublicKey) -> Result<SharedSecret, Self::Error> {
775 let mut out = [0u8; 32];
776 for (index, byte) in out.iter_mut().enumerate() {
777 *byte = self.public_key.0[index] ^ peer.0[index];
778 }
779 Ok(SharedSecret(out))
780 }
781}
782
783pub struct DummyCipher {
787 key: [u8; 16],
788}
789
790impl AesCipher for DummyCipher {
791 fn encrypt_block(&self, block: &mut [u8; 16]) {
792 for (byte, key) in block.iter_mut().zip(self.key.iter()) {
793 *byte ^= *key;
794 }
795 }
796
797 fn decrypt_block(&self, block: &mut [u8; 16]) {
798 self.encrypt_block(block);
799 }
800}
801
802#[derive(Clone, Copy)]
806pub struct DummyAes;
807
808impl AesProvider for DummyAes {
809 type Cipher = DummyCipher;
810
811 fn new_cipher(&self, key: &[u8; 16]) -> Self::Cipher {
812 DummyCipher { key: *key }
813 }
814}
815
816#[derive(Clone, Copy)]
820pub struct DummySha;
821
822impl Sha256Provider for DummySha {
823 fn hash(&self, data: &[&[u8]]) -> [u8; 32] {
824 let mut out = [0u8; 32];
825 for chunk in data {
826 for (index, byte) in chunk.iter().enumerate() {
827 out[index % 32] ^= *byte;
828 }
829 }
830 out
831 }
832
833 fn hmac(&self, key: &[u8], data: &[&[u8]]) -> [u8; 32] {
834 let mut out = [0u8; 32];
835 for (index, byte) in key.iter().enumerate() {
836 out[index % 32] ^= *byte;
837 }
838 for chunk in data {
839 for (index, byte) in chunk.iter().enumerate() {
840 out[index % 32] ^= *byte;
841 }
842 }
843 out
844 }
845}
846
847#[derive(Clone, Default)]
849pub struct DummyClock {
850 now_ms: Rc<Cell<u64>>,
851}
852
853impl DummyClock {
854 pub fn new(now_ms: u64) -> Self {
856 Self {
857 now_ms: Rc::new(Cell::new(now_ms)),
858 }
859 }
860
861 pub fn advance_ms(&self, delta_ms: u64) {
863 self.now_ms.set(self.now_ms.get().saturating_add(delta_ms));
864 }
865
866 pub fn set_ms(&self, now_ms: u64) {
868 self.now_ms.set(now_ms);
869 }
870}
871
872impl Clock for DummyClock {
873 fn now_ms(&self) -> u64 {
874 self.now_ms.get()
875 }
876}
877
878#[derive(Clone, Copy, Default)]
880pub struct DummyDelay;
881
882impl DelayNs for DummyDelay {
883 async fn delay_ns(&mut self, _ns: u32) {}
884}
885
886#[derive(Clone, Default)]
890pub struct DummyRng(pub u8);
891
892impl TryRng for DummyRng {
893 type Error = Infallible;
894
895 fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
896 let mut bytes = [0u8; 4];
897 self.fill_bytes(&mut bytes);
898 Ok(u32::from_le_bytes(bytes))
899 }
900
901 fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
902 let mut bytes = [0u8; 8];
903 self.fill_bytes(&mut bytes);
904 Ok(u64::from_le_bytes(bytes))
905 }
906
907 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Infallible> {
908 for byte in dest.iter_mut() {
909 *byte = self.0;
910 self.0 = self.0.wrapping_add(1);
911 }
912 Ok(())
913 }
914}
915
916impl TryCryptoRng for DummyRng {}
917
918#[derive(Clone, Copy, Default)]
920pub struct DummyCounterStore;
921
922impl CounterStore for DummyCounterStore {
923 type Error = ();
924
925 async fn load(&self, _context: &[u8]) -> Result<u32, Self::Error> {
926 Ok(0)
927 }
928
929 async fn store(&self, _context: &[u8], _value: u32) -> Result<(), Self::Error> {
930 Ok(())
931 }
932
933 async fn flush(&self) -> Result<(), Self::Error> {
934 Ok(())
935 }
936}
937
938#[derive(Clone, Copy, Default)]
940pub struct DummyKeyValueStore;
941
942impl KeyValueStore for DummyKeyValueStore {
943 type Error = ();
944
945 async fn load(&self, _key: &[u8], _buf: &mut [u8]) -> Result<Option<usize>, Self::Error> {
946 Ok(None)
947 }
948
949 async fn store(&self, _key: &[u8], _value: &[u8]) -> Result<(), Self::Error> {
950 Ok(())
951 }
952
953 async fn delete(&self, _key: &[u8]) -> Result<(), Self::Error> {
954 Ok(())
955 }
956}