Now let's take a silly one
0

Configure Feed

Select the types of activity you want to include in your feed.

at main 2.5 kB View raw
1use std::sync::Arc; 2use std::sync::atomic::{AtomicU64, Ordering}; 3use std::time::{SystemTime, UNIX_EPOCH}; 4 5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 6pub struct UnixMicros(u64); 7 8impl UnixMicros { 9 pub const fn new(micros: u64) -> Self { 10 Self(micros) 11 } 12 13 pub const fn get(self) -> u64 { 14 self.0 15 } 16} 17 18pub trait Clock: Send + Sync + 'static { 19 fn now_unix_micros(&self) -> UnixMicros; 20} 21 22impl<T: Clock + ?Sized> Clock for Arc<T> { 23 fn now_unix_micros(&self) -> UnixMicros { 24 (**self).now_unix_micros() 25 } 26} 27 28pub struct SystemClock; 29 30impl Clock for SystemClock { 31 fn now_unix_micros(&self) -> UnixMicros { 32 let micros = SystemTime::now() 33 .duration_since(UNIX_EPOCH) 34 .map(|elapsed| elapsed.as_micros() as u64) 35 .unwrap_or(0); 36 UnixMicros::new(micros) 37 } 38} 39 40pub struct ManualClock { 41 micros: AtomicU64, 42} 43 44impl ManualClock { 45 pub fn new(start: UnixMicros) -> Self { 46 Self { 47 micros: AtomicU64::new(start.get()), 48 } 49 } 50 51 pub fn advance(&self, micros: u64) { 52 self.micros.fetch_add(micros, Ordering::SeqCst); 53 } 54} 55 56impl Clock for ManualClock { 57 fn now_unix_micros(&self) -> UnixMicros { 58 UnixMicros::new(self.micros.load(Ordering::SeqCst)) 59 } 60} 61 62#[cfg(test)] 63mod tests { 64 use super::*; 65 66 #[test] 67 fn manual_clock_advances() { 68 let clock = ManualClock::new(UnixMicros::new(1_000)); 69 assert_eq!(clock.now_unix_micros().get(), 1_000); 70 clock.advance(500); 71 assert_eq!(clock.now_unix_micros().get(), 1_500); 72 } 73 74 #[test] 75 fn manual_clock_same_start_same_sequence() { 76 let one = ManualClock::new(UnixMicros::new(1_000)); 77 let two = ManualClock::new(UnixMicros::new(1_000)); 78 let advances = [10, 250, 7, 1_000]; 79 advances.iter().for_each(|&step| { 80 one.advance(step); 81 two.advance(step); 82 assert_eq!(one.now_unix_micros(), two.now_unix_micros()); 83 }); 84 } 85 86 #[test] 87 fn system_clock_is_after_epoch() { 88 assert!(SystemClock.now_unix_micros().get() > 0); 89 } 90 91 #[test] 92 fn a_shared_clock_advances_through_the_trait_object() { 93 let shared = Arc::new(ManualClock::new(UnixMicros::new(1_000))); 94 let view: Arc<dyn Clock> = Arc::clone(&shared) as Arc<dyn Clock>; 95 assert_eq!(view.now_unix_micros().get(), 1_000); 96 shared.advance(250); 97 assert_eq!(view.now_unix_micros().get(), 1_250); 98 } 99}