wtx/misc/
filled_buffer.rs1use crate::{
2 collection::Vector,
3 misc::{Lease, LeaseMut},
4};
5use core::{
6 fmt::Debug,
7 ops::{Deref, DerefMut},
8 slice,
9};
10
11#[derive(Debug, Default)]
13pub struct FilledBuffer {
14 data: Vector<u8>,
15}
16
17impl FilledBuffer {
18 pub(crate) fn from_vector(mut vector: Vector<u8>) -> Self {
19 let prev_init = vector.len();
20 unsafe {
22 fill_remaining_capacity(&mut vector, prev_init);
23 }
24 Self { data: vector }
25 }
26
27 pub(crate) fn all(&self) -> &[u8] {
28 unsafe {
30 let len = self.data.capacity();
31 slice::from_raw_parts(self.data.as_ptr(), len)
32 }
33 }
34
35 pub(crate) fn all_mut(&mut self) -> &mut [u8] {
36 unsafe {
38 let len = self.data.capacity();
39 slice::from_raw_parts_mut(self.data.as_ptr_mut(), len)
40 }
41 }
42
43 pub(crate) fn capacity(&self) -> usize {
44 self.data.capacity()
45 }
46
47 pub(crate) fn clear(&mut self) {
48 self.data.clear();
49 }
50
51 #[cfg(test)]
52 pub(crate) fn extend_from_slices<'iter, I>(&mut self, others: I) -> crate::Result<usize>
53 where
54 I: IntoIterator<Item = &'iter [u8]>,
55 I::IntoIter: Clone,
56 {
57 let prev_init = self.data.capacity();
58 let len = self.data.extend_from_copyable_slices(others)?;
59 unsafe {
61 fill_remaining_capacity(&mut self.data, prev_init);
62 }
63 Ok(len)
64 }
65
66 #[inline(always)]
67 pub(crate) fn reserve(&mut self, additional: usize) -> crate::Result<()> {
68 let prev_init = self.data.capacity();
69 self.data.reserve(additional)?;
70 unsafe {
72 fill_remaining_capacity(&mut self.data, prev_init);
73 }
74 Ok(())
75 }
76
77 pub(crate) fn set_len(&mut self, mut len: usize) {
78 len = len.min(self.data.capacity());
79 unsafe { self.data.set_len(len) }
81 }
82}
83
84#[cfg(any(feature = "mysql", feature = "postgres", feature = "web-socket"))]
85impl FilledBuffer {
86 pub(crate) fn with_capacity(capacity: usize) -> crate::Result<Self> {
87 let mut data = Vector::with_capacity(capacity)?;
88 unsafe {
90 slice::from_raw_parts_mut(data.as_ptr_mut(), data.capacity()).fill(0);
91 }
92 Ok(Self { data })
93 }
94}
95
96#[cfg(any(feature = "postgres", feature = "web-socket-handshake"))]
97impl FilledBuffer {
98 pub(crate) fn vector_mut(&mut self) -> FilledBufferVectorMut<'_> {
99 FilledBufferVectorMut { prev_init: self.data.capacity(), vector: &mut self.data }
100 }
101}
102
103impl Deref for FilledBuffer {
104 type Target = [u8];
105
106 #[inline]
107 fn deref(&self) -> &Self::Target {
108 self.data.as_slice()
109 }
110}
111
112impl DerefMut for FilledBuffer {
113 #[inline]
114 fn deref_mut(&mut self) -> &mut Self::Target {
115 self.data.as_slice_mut()
116 }
117}
118
119impl From<FilledBuffer> for Vector<u8> {
120 #[inline]
121 fn from(from: FilledBuffer) -> Self {
122 from.data
123 }
124}
125
126impl From<Vector<u8>> for FilledBuffer {
127 #[inline]
128 fn from(from: Vector<u8>) -> Self {
129 Self::from_vector(from)
130 }
131}
132
133#[cfg(feature = "std")]
134impl std::io::Write for FilledBuffer {
135 #[inline]
136 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
137 self.data.write(buf)
138 }
139
140 #[inline]
141 fn flush(&mut self) -> std::io::Result<()> {
142 self.data.flush()
143 }
144}
145
146#[derive(Debug)]
148pub struct FilledBufferVectorMut<'fb> {
149 prev_init: usize,
150 vector: &'fb mut Vector<u8>,
151}
152
153impl Lease<Vector<u8>> for FilledBufferVectorMut<'_> {
154 #[inline]
155 fn lease(&self) -> &Vector<u8> {
156 self.vector
157 }
158}
159
160impl LeaseMut<Vector<u8>> for FilledBufferVectorMut<'_> {
161 #[inline]
162 fn lease_mut(&mut self) -> &mut Vector<u8> {
163 self.vector
164 }
165}
166
167impl Drop for FilledBufferVectorMut<'_> {
168 #[inline]
169 fn drop(&mut self) {
170 unsafe {
172 fill_remaining_capacity(self.vector, self.prev_init);
173 }
174 }
175}
176
177unsafe fn fill_remaining_capacity(data: &mut Vector<u8>, prev_init: usize) {
178 let count = data.len().max(prev_init);
179 let Some(diff @ 1..=usize::MAX) = data.capacity().checked_sub(count) else {
180 return;
181 };
182 let ptr = unsafe { data.as_ptr_mut().add(count) };
184 unsafe {
186 slice::from_raw_parts_mut(ptr, diff).fill(0);
187 }
188}
189
190#[cfg(kani)]
191mod kani {
192 use crate::misc::filled_buffer::FilledBuffer;
193
194 #[kani::proof]
195 fn reserve_is_allocation() {
196 let reserve: u8 = kani::any();
197 let mut vec = FilledBuffer::_new();
198 vec._reserve(reserve.into()).unwrap();
199 assert!(vec._capacity() >= reserve.into());
200 assert!(vec._all_mut().len() >= reserve.into());
201 assert_eq!(vec.len(), 0);
202 let len = 16usize.min(reserve.into());
203 vec._set_len(len);
204 assert_eq!(vec.len(), len);
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use crate::misc::FilledBuffer;
211
212 #[test]
213 fn extend_from_slices_with_increasing_cap() {
214 let mut vec = FilledBuffer::default();
215 let _ = vec.extend_from_slices([&[1, 2, 3][..]]).unwrap();
216 assert_eq!(&*vec, &[1, 2, 3]);
217 }
218}