Skip to main content

std_ext/
lib.rs

1use core::sync::atomic::{AtomicBool, AtomicI64, AtomicIsize, AtomicU64, AtomicUsize};
2use std::sync::Arc;
3
4pub use map::{CacheMapExt, EntryExt, TimedValue};
5pub use wrapper::{HashExt, OrdExt, OrdHashExt};
6
7pub mod map;
8pub mod wrapper;
9
10#[macro_export]
11macro_rules! tuple_deref {
12    ($Name:ty) => {
13        impl<T> std::ops::Deref for $Name {
14            type Target = T;
15            #[inline]
16            fn deref(&self) -> &Self::Target {
17                &self.0
18            }
19        }
20    };
21}
22
23#[macro_export]
24macro_rules! tuple_deref_mut {
25    ($Name:ty) => {
26        impl<T> std::ops::DerefMut for $Name {
27            fn deref_mut(&mut self) -> &mut Self::Target {
28                &mut self.0
29            }
30        }
31    };
32}
33
34#[macro_export]
35macro_rules! tuple_take {
36    ($Name:ty) => {
37        impl<T> $Name {
38            #[inline]
39            pub fn take(self) -> T {
40                self.0
41            }
42        }
43    };
44}
45
46impl<T: ?Sized> ArcExt for T {}
47
48pub trait ArcExt {
49    #[inline]
50    fn arc(self) -> Arc<Self>
51    where
52        Self: Sized,
53    {
54        Arc::new(self)
55    }
56}
57
58pub trait AtomicExt<T> {
59    fn atomic(self) -> T;
60}
61
62impl AtomicExt<AtomicUsize> for usize {
63    #[inline]
64    fn atomic(self) -> AtomicUsize {
65        AtomicUsize::new(self)
66    }
67}
68
69impl AtomicExt<AtomicIsize> for isize {
70    #[inline]
71    fn atomic(self) -> AtomicIsize {
72        AtomicIsize::new(self)
73    }
74}
75
76impl AtomicExt<AtomicU64> for u64 {
77    #[inline]
78    fn atomic(self) -> AtomicU64 {
79        AtomicU64::new(self)
80    }
81}
82
83impl AtomicExt<AtomicI64> for i64 {
84    #[inline]
85    fn atomic(self) -> AtomicI64 {
86        AtomicI64::new(self)
87    }
88}
89
90impl AtomicExt<AtomicBool> for bool {
91    #[inline]
92    fn atomic(self) -> AtomicBool {
93        AtomicBool::new(self)
94    }
95}
96
97#[test]
98fn test_atomic() {
99    use std::sync::atomic::Ordering;
100
101    assert_eq!(100usize.atomic().load(Ordering::SeqCst), 100);
102    assert_eq!(100isize.atomic().load(Ordering::SeqCst), 100);
103    assert_eq!(100u64.atomic().load(Ordering::SeqCst), 100);
104    assert_eq!(100i64.atomic().load(Ordering::SeqCst), 100);
105    assert!(true.atomic().load(Ordering::SeqCst))
106}
107
108#[test]
109fn test_arc_ext() {
110    let v = 42.arc();
111    assert_eq!(*v, 42);
112
113    let s = "hello".to_string().arc();
114    assert_eq!(*s, "hello");
115
116    // Arc is cloneable
117    let s2 = s.clone();
118    assert_eq!(*s2, "hello");
119    assert!(Arc::ptr_eq(&s, &s2));
120}
121
122#[test]
123fn test_atomic_ext_usize() {
124    use std::sync::atomic::Ordering;
125    let a = 0usize.atomic();
126    a.store(10, Ordering::SeqCst);
127    assert_eq!(a.load(Ordering::SeqCst), 10);
128}
129
130#[test]
131fn test_atomic_ext_isize() {
132    use std::sync::atomic::Ordering;
133    let a = (-5isize).atomic();
134    assert_eq!(a.load(Ordering::SeqCst), -5);
135}
136
137#[test]
138fn test_atomic_ext_bool() {
139    use std::sync::atomic::Ordering;
140    let a = false.atomic();
141    assert!(!a.load(Ordering::SeqCst));
142    a.store(true, Ordering::SeqCst);
143    assert!(a.load(Ordering::SeqCst));
144}
145
146#[test]
147fn test_tuple_deref_macro() {
148    struct MyWrapper<T>(T);
149    tuple_deref!(MyWrapper<T>);
150
151    let w = MyWrapper(42);
152    assert_eq!(*w, 42);
153}
154
155#[test]
156fn test_tuple_deref_mut_macro() {
157    struct MyWrapper<T>(T);
158    tuple_deref!(MyWrapper<T>);
159    tuple_deref_mut!(MyWrapper<T>);
160
161    let mut w = MyWrapper(42);
162    *w = 100;
163    assert_eq!(*w, 100);
164}
165
166#[test]
167fn test_tuple_take_macro() {
168    struct MyWrapper<T>(T);
169    tuple_take!(MyWrapper<T>);
170
171    let w = MyWrapper(42);
172    assert_eq!(w.take(), 42);
173}
174
175#[test]
176fn test_wrapper_eq_ord() {
177    let a = 1.eq_ord();
178    let b = 2.eq_ord();
179    // EqOrdWrapper always compares equal
180    assert!(a.eq(&b));
181    assert!(a.partial_cmp(&b) == Some(std::cmp::Ordering::Equal));
182    assert!(a.cmp(&b) == std::cmp::Ordering::Equal);
183}
184
185#[test]
186fn test_wrapper_neq_ord() {
187    let a = 1.neq_ord();
188    let b = 1.neq_ord();
189    // NeqOrdWrapper never compares equal
190    assert!(a.ne(&b));
191    assert!(a.partial_cmp(&b).is_none());
192    assert!(a.cmp(&b) == std::cmp::Ordering::Greater);
193}
194
195#[test]
196fn test_wrapper_hash() {
197    use std::collections::hash_map::DefaultHasher;
198    use std::hash::{Hash, Hasher};
199
200    let a = 42.hash_value(12345);
201    let mut hasher = DefaultHasher::new();
202    a.hash(&mut hasher);
203    let h1 = hasher.finish();
204
205    let b = 99.hash_value(12345);
206    let mut hasher2 = DefaultHasher::new();
207    b.hash(&mut hasher2);
208    let h2 = hasher2.finish();
209
210    // Same hash value → same hash output
211    assert_eq!(h1, h2);
212
213    // Different hash value → different hash output
214    let c = 42.hash_value(54321);
215    let mut hasher3 = DefaultHasher::new();
216    c.hash(&mut hasher3);
217    let h3 = hasher3.finish();
218    assert_ne!(h1, h3);
219}
220
221#[test]
222fn test_empty_hash_wrapper() {
223    use std::collections::hash_map::DefaultHasher;
224    use std::hash::{Hash, Hasher};
225
226    let a = 42.hash_empty();
227    let mut hasher = DefaultHasher::new();
228    a.hash(&mut hasher);
229    let h1 = hasher.finish();
230
231    let b = 99.hash_empty();
232    let mut hasher2 = DefaultHasher::new();
233    b.hash(&mut hasher2);
234    let h2 = hasher2.finish();
235
236    // Empty hash wrapper always produces the same hash (empty)
237    let h_default = DefaultHasher::new().finish();
238    assert_eq!(h1, h_default);
239    assert_eq!(h2, h_default);
240}
241
242#[test]
243fn test_ord_hash_ext_neq_ord_hash() {
244    let a = 1.neq_ord_hash(100);
245    let b = 1.neq_ord_hash(100);
246    // NeqOrdHashWrapper never compares equal even with same values
247    assert!(a.ne(&b));
248}
249
250#[test]
251fn test_ord_hash_ext_neq_ord_empty() {
252    let a = 1.neq_ord_empty();
253    let b = 1.neq_ord_empty();
254    // NeqOrdEmptyHashWrapper never compares equal
255    assert!(a.ne(&b));
256    assert!(a.cmp(&b) == std::cmp::Ordering::Greater);
257}
258
259#[test]
260fn test_ord_ext_reverse_via_cmp() {
261    // OrdExt itself doesn't have reverse(), but we verify default methods work
262    let a = 5.eq_ord();
263    assert!(a.cmp(&6.eq_ord()) == std::cmp::Ordering::Equal);
264    assert!(5.neq_ord().cmp(&5.neq_ord()) == std::cmp::Ordering::Greater);
265}