custos/
count.rs

1use core::ops::{Range, RangeInclusive};
2
3/// Converts ranges into a start and end index.
4pub trait AsRangeArg {
5    /// Returns the start index of the range.
6    fn start(&self) -> usize;
7    /// Returns the end index of the range.
8    fn end(&self) -> usize;
9}
10
11impl AsRangeArg for Range<usize> {
12    #[inline]
13    fn start(&self) -> usize {
14        self.start
15    }
16
17    #[inline]
18    fn end(&self) -> usize {
19        self.end
20    }
21}
22
23impl AsRangeArg for RangeInclusive<usize> {
24    #[inline]
25    fn start(&self) -> usize {
26        *self.start()
27    }
28
29    #[inline]
30    fn end(&self) -> usize {
31        *self.end() + 1
32    }
33}
34
35impl AsRangeArg for usize {
36    #[inline]
37    fn start(&self) -> usize {
38        0
39    }
40
41    #[inline]
42    fn end(&self) -> usize {
43        *self
44    }
45}
46
47impl AsRangeArg for (usize, usize) {
48    #[inline]
49    fn start(&self) -> usize {
50        self.0
51    }
52
53    #[inline]
54    fn end(&self) -> usize {
55        self.1
56    }
57}
58
59/// `range` resets the cache count in every iteration.
60/// The cache count is used to retrieve the same allocation in each iteration.
61/// Not adding `range` results in allocating new memory in each iteration, 
62/// which is only freed when the device is dropped. <br>
63/// To disable this caching behaviour, the `realloc` feature can be enabled.
64/// 
65/// # Example
66#[cfg_attr(not(feature = "no-std"), doc = "```")]
67#[cfg_attr(feature = "no-std", doc = "```ignore")]
68/// use custos::{get_count, range, Ident, bump_count};
69///
70/// for _ in range(100) { // using only one usize: exclusive range
71///     Ident::new(10); // an 'Ident' is created if a Buffer is retrieved from cache.
72///     bump_count();
73///     assert!(get_count() == 1);
74/// }
75/// assert!(get_count() == 0);
76/// ```
77#[inline]
78pub fn range<R: AsRangeArg>(range: R) -> Count {
79    Count(range.start(), range.end())
80}
81
82/// used to reset the cache count
83#[derive(Debug, Clone, Copy)]
84pub struct Count(pub(super) usize, pub(super) usize);
85
86/// The iterator used for setting the cache count.
87#[derive(Debug)]
88pub struct CountIntoIter {
89    epoch: usize,
90    #[cfg(not(feature = "no-std"))]
91    idx: usize,
92    end: usize,
93}
94
95impl Iterator for CountIntoIter {
96    type Item = usize;
97
98    fn next(&mut self) -> Option<Self::Item> {
99        #[cfg(not(feature = "no-std"))]
100        unsafe {
101            crate::set_count(self.idx)
102        };
103        if self.epoch >= self.end {
104            return None;
105        }
106        let epoch = Some(self.epoch);
107        self.epoch += 1;
108        epoch
109    }
110}
111
112impl IntoIterator for Count {
113    type Item = usize;
114
115    type IntoIter = CountIntoIter;
116
117    #[inline]
118    fn into_iter(self) -> Self::IntoIter {
119        CountIntoIter {
120            epoch: self.0,
121            #[cfg(not(feature = "no-std"))]
122            idx: crate::get_count(),
123            end: self.1,
124        }
125    }
126}
127
128#[cfg(test)]
129mod tests {
130    use crate::{range, Count, CountIntoIter};
131
132    fn count_iter(iter: &mut CountIntoIter) {
133        iter.next();
134        assert_eq!(iter.epoch, 1);
135        #[cfg(not(feature = "no-std"))]
136        assert_eq!(iter.idx, 0);
137        assert_eq!(iter.end, 10);
138
139        iter.next();
140        assert_eq!(iter.epoch, 2);
141        #[cfg(not(feature = "no-std"))]
142        assert_eq!(iter.idx, 0);
143        assert_eq!(iter.end, 10);
144    }
145
146    #[test]
147    fn test_count_into_iter() {
148        let mut iter = CountIntoIter {
149            epoch: 0,
150            #[cfg(not(feature = "no-std"))]
151            idx: 0,
152            end: 10,
153        };
154
155        count_iter(&mut iter);
156    }
157
158    #[test]
159    fn test_count() {
160        let count: Count = Count(0, 10);
161        count_iter(&mut count.into_iter());
162    }
163
164    #[test]
165    fn test_range_inclusive() {
166        let count: Count = range(0..=9);
167        count_iter(&mut count.into_iter());
168
169        for (idx, other) in count.into_iter().zip(0..=9) {
170            assert_eq!(idx, other)
171        }
172    }
173}