1 //! limit defines a struct to enforce limits.
2 
3 use std::sync::atomic::AtomicUsize;
4 
5 /// Represents a struct used to enforce a numerical limit.
6 pub struct Limit {
7     upper_bound: usize,
8     #[allow(unused)]
9     max: AtomicUsize,
10 }
11 
12 impl Limit {
13     /// Creates a new limit.
14     #[inline]
new(upper_bound: usize) -> Self15     pub const fn new(upper_bound: usize) -> Self {
16         Self { upper_bound, max: AtomicUsize::new(0) }
17     }
18 
19     /// Creates a new limit.
20     #[inline]
21     #[cfg(feature = "tracking")]
new_tracking(upper_bound: usize) -> Self22     pub const fn new_tracking(upper_bound: usize) -> Self {
23         Self { upper_bound, max: AtomicUsize::new(1) }
24     }
25 
26     /// Gets the underlying numeric limit.
27     #[inline]
inner(&self) -> usize28     pub const fn inner(&self) -> usize {
29         self.upper_bound
30     }
31 
32     /// Checks whether the given value is below the limit.
33     /// Returns `Ok` when `other` is below `self`, and `Err` otherwise.
34     #[inline]
check(&self, other: usize) -> Result<(), ()>35     pub fn check(&self, other: usize) -> Result<(), ()> {
36         if other > self.upper_bound {
37             Err(())
38         } else {
39             #[cfg(feature = "tracking")]
40             loop {
41                 use std::sync::atomic::Ordering;
42                 let old_max = self.max.load(Ordering::Relaxed);
43                 if other <= old_max || old_max == 0 {
44                     break;
45                 }
46                 if self
47                     .max
48                     .compare_exchange(old_max, other, Ordering::Relaxed, Ordering::Relaxed)
49                     .is_ok()
50                 {
51                     eprintln!("new max: {}", other);
52                 }
53             }
54 
55             Ok(())
56         }
57     }
58 }
59