flex_alloc/
capacity.rs

1//! Types used to specify indexes, ranges, lengths, and capacities of collections.
2
3use core::fmt::{Debug, Display};
4
5use crate::storage::utils::min_non_zero_cap;
6
7/// Types which may be used to index and define the length and capacity of collections.
8pub trait Index:
9    Copy
10    + Clone
11    + Debug
12    + Display
13    + Into<usize>
14    + PartialEq
15    + Eq
16    + PartialOrd
17    + Ord
18    + Send
19    + Sync
20    + Sized
21    + 'static
22{
23    /// The zero value
24    const ZERO: Self;
25    /// The maximum representable value of this type as a `usize`
26    const MAX_USIZE: usize;
27
28    /// Create an instance of this type from a usize, panicking if
29    /// the bounds are exceeded
30    fn from_usize(val: usize) -> Self;
31
32    /// Try to create an instance of this type from a usize
33    fn try_from_usize(val: usize) -> Option<Self>;
34
35    /// Convert this instance into a `usize`
36    #[inline]
37    fn to_usize(self) -> usize {
38        self.into()
39    }
40
41    /// Add a `usize` without exceeding the bounds of this type
42    fn saturating_add(self, val: usize) -> Self;
43
44    /// Subtract a `usize` without exceeding the bounds of this type
45    fn saturating_sub(self, val: usize) -> Self;
46
47    /// Multiply by a `usize` without exceeding the bounds of this type
48    fn saturating_mul(self, val: usize) -> Self;
49}
50
51impl Index for u8 {
52    const ZERO: Self = 0u8;
53    const MAX_USIZE: usize = u8::MAX as usize;
54
55    #[inline]
56    fn from_usize(val: usize) -> Self {
57        val as Self
58    }
59
60    #[inline]
61    fn try_from_usize(val: usize) -> Option<Self> {
62        val.try_into().ok()
63    }
64
65    #[inline]
66    fn to_usize(self) -> usize {
67        self as usize
68    }
69
70    #[inline]
71    fn saturating_add(self, val: usize) -> Self {
72        // self.to_usize().saturating_add(val).min(Self::MAX_USIZE) as Self
73        (self as usize + val) as Self
74        // self + (val as Self)
75    }
76
77    fn saturating_sub(self, val: usize) -> Self {
78        self.to_usize().saturating_sub(val) as Self
79    }
80
81    fn saturating_mul(self, val: usize) -> Self {
82        self.to_usize().saturating_mul(val).min(Self::MAX_USIZE) as Self
83    }
84}
85
86impl Index for usize {
87    const ZERO: Self = 0usize;
88    const MAX_USIZE: usize = usize::MAX;
89
90    #[inline]
91    fn from_usize(val: usize) -> Self {
92        val
93    }
94
95    #[inline]
96    fn try_from_usize(val: usize) -> Option<Self> {
97        Some(val)
98    }
99
100    fn saturating_add(self, val: usize) -> Self {
101        self.saturating_add(val)
102    }
103
104    fn saturating_sub(self, val: usize) -> Self {
105        self.saturating_sub(val)
106    }
107
108    fn saturating_mul(self, val: usize) -> Self {
109        self.saturating_mul(val)
110    }
111}
112
113/// Growth behavior for collections which have exceeded their available storage
114pub trait Grow: Debug {
115    /// Calculate the next capacity to request from the allocator
116    fn next_capacity<T, I: Index>(prev: I, minimum: I) -> I;
117}
118
119/// Growth behavior which never requests extra capacity
120#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
121pub struct GrowExact;
122
123impl Grow for GrowExact {
124    #[inline]
125    fn next_capacity<T, I: Index>(_prev: I, minimum: I) -> I {
126        minimum
127    }
128}
129
130/// Growth behavior which consistently doubles in size
131#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
132pub struct GrowDoubling;
133
134impl Grow for GrowDoubling {
135    #[inline]
136    fn next_capacity<T, I: Index>(prev: I, minimum: I) -> I {
137        let preferred = if prev == I::ZERO {
138            I::from_usize(min_non_zero_cap::<T>())
139        } else {
140            prev.saturating_mul(2)
141        };
142        preferred.max(minimum)
143    }
144}