cryprot_core/
buf.rs

1//! Owned buffer abstraction trait for [`Vec`] and [`HugePageMemory`].
2//!
3//! The sealed [`Buf`] trait allows write code generic [`Vec`] or
4//! [`HugePageMemory`]
5use std::{
6    fmt::Debug,
7    ops::{Deref, DerefMut},
8};
9
10use bytemuck::Zeroable;
11
12use crate::alloc::{HugePageMemory, allocate_zeroed_vec};
13
14pub trait Buf<T>:
15    Default + Debug + Deref<Target = [T]> + DerefMut + Send + Sync + 'static + private::Sealed
16{
17    /// Create a new `Buf` of length `len` with all elements set to zero.
18    ///
19    /// Implementations of this directly allocate zeroed memory and do not write
20    /// zeroes to the elements explicitly.
21    fn zeroed(len: usize) -> Self;
22
23    /// Create a new [`Buf`] of the same kind but for two-element arrays of
24    /// `T``.
25    ///
26    /// This method is useful in methods generic over Buf which need a temporary
27    /// buffer over arrays of size two of `T`, that is the same kind of buffer
28    /// the method is called with. That is, a `fn foo(b: impl Buf<T>)`
29    /// called with a [`HugePageMemory`] can use this method to create a
30    /// `HugePageMemory<[T;2]>`.
31    //
32    // Note: Ideally we would use a GAT on Buf for this, but sadly due to
33    // https://github.com/rust-lang/rust-analyzer/issues/19502 in rust-analyzer,
34    // this renders autocomplete unusable in methods generic over Buf.
35    fn zeroed_arr2(len: usize) -> impl Buf<[T; 2]>;
36
37    /// Capacity of the `Buf`.
38    fn capacity(&self) -> usize;
39
40    /// Sets the length of the buffer
41    /// # Panic
42    /// Panics if `len > self.capacity`.
43    fn set_len(&mut self, new_len: usize);
44
45    /// Grow the `Buf` to `new_size` and fill with zeroes.
46    ///
47    /// ```
48    /// # use cryprot_core::buf::Buf;
49    /// let mut v: Vec<u8> = Vec::zeroed(20);
50    /// assert_eq!(20, v.len());
51    /// v.grow_zeroed(40);
52    /// assert_eq!(40, v.len());
53    /// ```
54    fn grow_zeroed(&mut self, new_size: usize);
55}
56
57impl<T: Zeroable + Clone + Default + Debug + Send + Sync + 'static> Buf<T> for Vec<T> {
58    fn zeroed(len: usize) -> Self {
59        allocate_zeroed_vec(len)
60    }
61
62    fn zeroed_arr2(len: usize) -> impl Buf<[T; 2]> {
63        allocate_zeroed_vec(len)
64    }
65
66    fn capacity(&self) -> usize {
67        self.capacity()
68    }
69
70    fn set_len(&mut self, new_len: usize) {
71        assert!(new_len <= self.capacity());
72        // SAFETY:
73        // new_len <= self.capacity
74        // self[len..new_len] is initialized either because of Self::zeroed
75        // or with data written to it.
76        unsafe {
77            self.set_len(new_len);
78        }
79    }
80
81    fn grow_zeroed(&mut self, new_size: usize) {
82        self.resize(new_size, T::zeroed());
83    }
84}
85
86impl<T: Zeroable + Clone + Default + Debug + Send + Sync + 'static> Buf<T> for HugePageMemory<T> {
87    fn zeroed(len: usize) -> Self {
88        HugePageMemory::zeroed(len)
89    }
90
91    fn zeroed_arr2(len: usize) -> impl Buf<[T; 2]> {
92        HugePageMemory::zeroed(len)
93    }
94
95    fn capacity(&self) -> usize {
96        self.capacity()
97    }
98
99    fn set_len(&mut self, new_len: usize) {
100        self.set_len(new_len);
101    }
102
103    fn grow_zeroed(&mut self, new_size: usize) {
104        self.grow_zeroed(new_size);
105    }
106}
107
108mod private {
109    use crate::alloc::HugePageMemory;
110
111    pub trait Sealed {}
112
113    impl<T> Sealed for Vec<T> {}
114    impl<T> Sealed for HugePageMemory<T> {}
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120
121    #[test]
122    fn test_buf() {
123        let buf = Vec::<u8>::zeroed(1024);
124        assert_eq!(buf.len(), 1024);
125        assert!(buf.iter().all(|&x| x == 0));
126    }
127}