unempty/
capacity.rs

1use std::{
2    cmp::{max, min},
3    fmt::Display,
4};
5
6/// Defines the capacity for a data structure, considering the non-empty nature of data structures in this crate.
7///
8/// Many data structures provide a `with_capacity` or similar constructor to enable pre-allocation.
9/// This has the potential to become confusing for users of a non-empty data structure:
10/// _is this capacity the full capacity, or the additional capacity?_
11///
12/// To prevent this confusion, this crate uses [`Capacity`] for these types of methods.
13///
14/// # `N` constant
15///
16/// The `N` constant is the capacity size of the statically sized portion of the data structure.
17/// For example, `unzero::Vec<T>` statically stores one `T`, so its value for `N` is 1.
18///
19/// # Kinds of capacity
20///
21/// - `total`: Total capacity means "this is the total size of the data structure,
22///   including the statically sized portion maintained by the non-empty data structure".
23/// - `dynamic`: Dynamic capacity means "this is the size of the dynamic portion of the data structure".
24///   Most non-empty data structures are backed by some other dynamically growable structure,
25///   this size represents the size of that structure directly.
26///
27/// For example, consider the following cases (`Vec` in the table below refers to [`unempty::Vec`]):
28///
29/// | Constructor                         | Total Capacity | Dynamic Capacity |
30/// | ----------------------------------- | -------------- | ---------------- |
31/// | `Vec::new(())`                      | 1              | 0                |
32/// | `Vec::with_capacity(10.into())`     | 10             | 9                |
33/// | `let v = Vec::new(()); v.push(());` | 2              | 1                |
34///
35/// # `From` conversions
36///
37/// The `From` conversions provided for this data structure take the more conservative route and
38/// treat the original value being converted from as _total_ capacity.
39///
40/// [Kinds of capacity]: #kinds-of-capacity
41#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
42pub struct Capacity<const N: usize> {
43    total: usize,
44    dynamic: usize,
45}
46
47impl<const N: usize> Capacity<N> {
48    /// Create a [`Capacity`] with the provided _total_ capacity.
49    /// If the provided total capacity is less than `N`, it is increased to `N`.
50    ///
51    /// For definitions on kinds of capacity, see *[Kinds of capacity]*.
52    pub fn new_total(capacity: usize) -> Self {
53        let total = max(capacity, N);
54        let dynamic = capacity - N;
55        Self { total, dynamic }
56    }
57
58    /// Create a [`Capacity`] with the provided capacity for the dynamic portion of the data structure.
59    /// If the provided dynamic capacity would cause an integer overflow when accounting for `N`,
60    /// the dynamic capacity is reduced to `usize::MAX - N`.
61    ///
62    /// For definitions on kinds of capacity, see *[Kinds of capacity]*.
63    pub fn new_dynamic(capacity: usize) -> Self {
64        let dynamic = min(capacity, usize::MAX - N);
65        let total = dynamic + N;
66        Self { total, dynamic }
67    }
68
69    /// Reference the _total_ capacity specified.
70    ///
71    /// For definitions on kinds of capacity, see *[Kinds of capacity]*.
72    pub fn total(&self) -> usize {
73        self.total
74    }
75
76    /// Reference the _dynamic_ capacity specified.
77    ///
78    /// For definitions on kinds of capacity, see *[Kinds of capacity]*.
79    pub fn dynamic(&self) -> usize {
80        self.dynamic
81    }
82
83    /// Reference the size of `N`.
84    pub fn sizeof_n() -> usize {
85        N
86    }
87}
88
89impl<I, const N: usize> From<I> for Capacity<N>
90where
91    I: Into<usize>,
92{
93    fn from(total_capacity: I) -> Self {
94        Self::new_total(total_capacity.into())
95    }
96}
97
98impl<const N: usize> Default for Capacity<N> {
99    fn default() -> Self {
100        Self::new_total(N)
101    }
102}
103
104impl<const N: usize> Display for Capacity<N> {
105    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        write!(
107            f,
108            "capacity(static_size: {}, dynamic_size: {})",
109            self.total, self.dynamic
110        )
111    }
112}