1use std::any::Any;
2use std::sync::Arc;
3use std::time::{SystemTime, UNIX_EPOCH};
4
5#[derive(Debug, Clone)]
10pub struct Token<T> {
11 value: Arc<T>,
12 created_at: u64,
13}
14
15impl<T> Token<T> {
16 pub fn new(value: T) -> Self {
18 Self {
19 value: Arc::new(value),
20 created_at: now_millis(),
21 }
22 }
23
24 pub fn at(value: T, created_at: u64) -> Self {
26 Self {
27 value: Arc::new(value),
28 created_at,
29 }
30 }
31
32 pub fn from_arc(value: Arc<T>, created_at: u64) -> Self {
34 Self { value, created_at }
35 }
36
37 pub fn value(&self) -> &T {
39 &self.value
40 }
41
42 pub fn value_arc(&self) -> Arc<T> {
44 Arc::clone(&self.value)
45 }
46
47 pub fn created_at(&self) -> u64 {
49 self.created_at
50 }
51}
52
53pub fn unit_token() -> Token<()> {
56 Token {
57 value: Arc::new(()),
58 created_at: 0,
59 }
60}
61
62#[derive(Debug, Clone)]
64pub struct ErasedToken {
65 pub value: Arc<dyn Any + Send + Sync>,
66 pub created_at: u64,
67}
68
69impl ErasedToken {
70 pub fn from_typed<T: Send + Sync + 'static>(token: &Token<T>) -> Self {
72 Self {
73 value: Arc::clone(&token.value) as Arc<dyn Any + Send + Sync>,
74 created_at: token.created_at,
75 }
76 }
77
78 pub fn downcast<T: Send + Sync + 'static>(&self) -> Option<Token<T>> {
80 self.value.downcast_ref::<T>().map(|_| {
81 let value = Arc::clone(&self.value);
83 let typed: Arc<T> = unsafe {
85 let raw = Arc::into_raw(value);
86 Arc::from_raw(raw.cast::<T>())
87 };
88 Token::from_arc(typed, self.created_at)
89 })
90 }
91}
92
93pub fn now_millis() -> u64 {
94 SystemTime::now()
95 .duration_since(UNIX_EPOCH)
96 .unwrap_or_default()
97 .as_millis() as u64
98}
99
100#[cfg(test)]
101mod tests {
102 use super::*;
103
104 #[test]
105 fn token_new_has_current_timestamp() {
106 let t = Token::new(42);
107 assert_eq!(*t.value(), 42);
108 assert!(t.created_at() > 0);
109 }
110
111 #[test]
112 fn token_at_preserves_timestamp() {
113 let t = Token::at("hello", 1000);
114 assert_eq!(*t.value(), "hello");
115 assert_eq!(t.created_at(), 1000);
116 }
117
118 #[test]
119 fn unit_token_has_zero_timestamp() {
120 let t = unit_token();
121 assert_eq!(*t.value(), ());
122 assert_eq!(t.created_at(), 0);
123 }
124
125 #[test]
126 fn token_clone_is_cheap() {
127 let t = Token::new(vec![1, 2, 3]);
128 let t2 = t.clone();
129 assert!(Arc::ptr_eq(&t.value, &t2.value));
130 }
131
132 #[test]
133 fn erased_token_roundtrip() {
134 let t = Token::new(42i32);
135 let erased = ErasedToken::from_typed(&t);
136 let recovered = erased.downcast::<i32>().unwrap();
137 assert_eq!(*recovered.value(), 42);
138 assert_eq!(recovered.created_at(), t.created_at());
139 }
140
141 #[test]
142 fn erased_token_wrong_type_returns_none() {
143 let t = Token::new(42i32);
144 let erased = ErasedToken::from_typed(&t);
145 assert!(erased.downcast::<String>().is_none());
146 }
147}