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}