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    #[inline]
30    fn increment(&mut self) {}
31    #[inline]
32    fn decrement(&mut self) {}
33    #[inline]
34    fn get(&self) -> usize {
35        panic!("Cannot get the size if we are not tracking the size.")
36    }
37    #[inline]
38    fn set(&mut self, _size: usize) {}
39    #[inline]
40    fn swap(&mut self, _other: &mut Self) {}
41}
42
43/// A size tracker that maintains the count of elements in the list.
44#[derive(Clone, Copy)]
45pub struct TrackingSize(usize);
46impl SizeTracker for TrackingSize {
47    const INIT: Self = TrackingSize(0);
48    const IS_TRACKING: bool = true;
49    #[inline]
50    fn increment(&mut self) {
51        self.0 += 1;
52    }
53    #[inline]
54    fn decrement(&mut self) {
55        self.0 -= 1;
56    }
57    #[inline]
58    fn get(&self) -> usize {
59        self.0
60    }
61    #[inline]
62    fn set(&mut self, size: usize) {
63        self.0 = size;
64    }
65    #[inline]
66    fn swap(&mut self, other: &mut Self) {
67        core::mem::swap(&mut self.0, &mut other.0);
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    #[should_panic(expected = "Cannot get the size if we are not tracking the size.")]
77    fn test_non_tracking_size_get_panics() {
78        let tracker = NonTrackingSize;
79        let _ = tracker.get();
80    }
81
82    #[test]
83    fn test_non_tracking_size_set_swap() {
84        let mut tracker1 = NonTrackingSize;
85        let mut tracker2 = NonTrackingSize;
86        tracker1.increment();
87        tracker1.decrement();
88        tracker1.set(10);
89        tracker1.swap(&mut tracker2);
90        assert!(!NonTrackingSize::IS_TRACKING);
91    }
92
93    #[test]
94    fn test_tracking_size_increment_decrement() {
95        let mut tracker = TrackingSize::INIT;
96        assert!(TrackingSize::IS_TRACKING);
97        assert_eq!(tracker.get(), 0);
98        tracker.increment();
99        assert_eq!(tracker.get(), 1);
100        tracker.increment();
101        assert_eq!(tracker.get(), 2);
102        tracker.decrement();
103        assert_eq!(tracker.get(), 1);
104    }
105
106    #[test]
107    fn test_tracking_size_set() {
108        let mut tracker = TrackingSize::INIT;
109        tracker.set(100);
110        assert_eq!(tracker.get(), 100);
111    }
112
113    #[test]
114    fn test_tracking_size_swap() {
115        let mut tracker1 = TrackingSize::INIT;
116        tracker1.set(100);
117        let mut tracker2 = TrackingSize::INIT;
118        tracker2.set(50);
119
120        tracker1.swap(&mut tracker2);
121        assert_eq!(tracker1.get(), 50);
122        assert_eq!(tracker2.get(), 100);
123    }
124}