Skip to main content

fbl/
size_tracker.rs

1// Copyright 2026 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5/// Trait for tracking the size of the list.
6pub trait SizeTracker: Clone {
7    /// The initial value for the tracker.
8    const INIT: Self;
9    /// True if this tracker actually tracks the size.
10    const IS_TRACKING: bool;
11    /// Increments the size count.
12    fn increment(&mut self);
13    /// Decrements the size count.
14    fn decrement(&mut self);
15    /// Returns the current size.
16    fn get(&self) -> usize;
17    /// Sets the size count.
18    fn set(&mut self, size: usize);
19    /// Swaps the size count with another tracker.
20    fn swap(&mut self, other: &mut Self);
21}
22
23/// A size tracker that does not actually track the size (zero overhead).
24#[derive(Clone, Copy)]
25pub struct NonTrackingSize;
26impl SizeTracker for NonTrackingSize {
27    const INIT: Self = NonTrackingSize;
28    const IS_TRACKING: bool = false;
29    fn increment(&mut self) {}
30    fn decrement(&mut self) {}
31    fn get(&self) -> usize {
32        panic!("Cannot get the size if we are not tracking the size.")
33    }
34    fn set(&mut self, _size: usize) {}
35    fn swap(&mut self, _other: &mut Self) {}
36}
37
38/// A size tracker that maintains the count of elements in the list.
39#[derive(Clone, Copy)]
40pub struct TrackingSize(usize);
41impl SizeTracker for TrackingSize {
42    const INIT: Self = TrackingSize(0);
43    const IS_TRACKING: bool = true;
44    fn increment(&mut self) {
45        self.0 += 1;
46    }
47    fn decrement(&mut self) {
48        self.0 -= 1;
49    }
50    fn get(&self) -> usize {
51        self.0
52    }
53    fn set(&mut self, size: usize) {
54        self.0 = size;
55    }
56    fn swap(&mut self, other: &mut Self) {
57        core::mem::swap(&mut self.0, &mut other.0);
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    #[should_panic(expected = "Cannot get the size if we are not tracking the size.")]
67    fn test_non_tracking_size_get_panics() {
68        let tracker = NonTrackingSize;
69        let _ = tracker.get();
70    }
71
72    #[test]
73    fn test_non_tracking_size_set_swap() {
74        let mut tracker1 = NonTrackingSize;
75        let mut tracker2 = NonTrackingSize;
76        tracker1.increment();
77        tracker1.decrement();
78        tracker1.set(10);
79        tracker1.swap(&mut tracker2);
80        assert!(!NonTrackingSize::IS_TRACKING);
81    }
82
83    #[test]
84    fn test_tracking_size_increment_decrement() {
85        let mut tracker = TrackingSize::INIT;
86        assert!(TrackingSize::IS_TRACKING);
87        assert_eq!(tracker.get(), 0);
88        tracker.increment();
89        assert_eq!(tracker.get(), 1);
90        tracker.increment();
91        assert_eq!(tracker.get(), 2);
92        tracker.decrement();
93        assert_eq!(tracker.get(), 1);
94    }
95
96    #[test]
97    fn test_tracking_size_set() {
98        let mut tracker = TrackingSize::INIT;
99        tracker.set(100);
100        assert_eq!(tracker.get(), 100);
101    }
102
103    #[test]
104    fn test_tracking_size_swap() {
105        let mut tracker1 = TrackingSize::INIT;
106        tracker1.set(100);
107        let mut tracker2 = TrackingSize::INIT;
108        tracker2.set(50);
109
110        tracker1.swap(&mut tracker2);
111        assert_eq!(tracker1.get(), 50);
112        assert_eq!(tracker2.get(), 100);
113    }
114}