Skip to content

Commit 30ef24c

Browse files
authored
feat(s2n-quic-core): add buffer::Deque implemention (#2207)
1 parent bd37960 commit 30ef24c

File tree

12 files changed

+1292
-7
lines changed

12 files changed

+1292
-7
lines changed

quic/s2n-quic-core/src/buffer.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4+
pub mod deque;
45
pub mod duplex;
56
mod error;
67
pub mod reader;
78
pub mod reassembler;
89
pub mod writer;
910

11+
pub use deque::Deque;
1012
pub use duplex::Duplex;
1113
pub use error::Error;
1214
pub use reader::Reader;
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
use crate::slice::deque;
5+
use alloc::{boxed::Box, vec::Vec};
6+
use core::{fmt, mem::MaybeUninit};
7+
8+
mod storage;
9+
10+
#[cfg(test)]
11+
mod tests;
12+
13+
/// A fixed-capacity ring buffer for bytes
14+
#[derive(Clone)]
15+
pub struct Deque {
16+
bytes: Box<[MaybeUninit<u8>]>,
17+
head: usize,
18+
len: usize,
19+
}
20+
21+
impl fmt::Debug for Deque {
22+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23+
f.debug_struct("Deque")
24+
.field("len", &self.len())
25+
.field("capacity", &self.capacity())
26+
.finish()
27+
}
28+
}
29+
30+
impl From<Vec<u8>> for Deque {
31+
#[inline]
32+
fn from(mut buffer: Vec<u8>) -> Deque {
33+
let len = buffer.len();
34+
let mut capacity = buffer.capacity();
35+
if !capacity.is_power_of_two() {
36+
capacity = capacity.next_power_of_two();
37+
buffer.reserve_exact(capacity - len);
38+
debug_assert!(capacity.is_power_of_two());
39+
}
40+
41+
unsafe {
42+
buffer.set_len(capacity);
43+
}
44+
45+
let bytes = buffer.into_boxed_slice();
46+
let ptr = Box::into_raw(bytes);
47+
let bytes = unsafe { Box::from_raw(ptr as *mut [MaybeUninit<u8>]) };
48+
49+
Self {
50+
bytes,
51+
head: 0,
52+
len,
53+
}
54+
}
55+
}
56+
57+
impl Deque {
58+
#[inline]
59+
pub fn new(mut capacity: usize) -> Self {
60+
// Make sure capacity is set to a power of two
61+
// https://doc.rust-lang.org/std/primitive.usize.html#method.next_power_of_two
62+
//> Returns the smallest power of two greater than or equal to self.
63+
capacity = capacity.next_power_of_two();
64+
65+
let mut bytes = Vec::<MaybeUninit<u8>>::with_capacity(capacity);
66+
unsafe {
67+
bytes.set_len(capacity);
68+
}
69+
let bytes = bytes.into_boxed_slice();
70+
71+
Self {
72+
bytes,
73+
head: 0,
74+
len: 0,
75+
}
76+
}
77+
78+
#[inline]
79+
pub fn capacity(&self) -> usize {
80+
self.bytes.len()
81+
}
82+
83+
#[inline]
84+
pub fn remaining_capacity(&self) -> usize {
85+
self.preconditions();
86+
self.capacity() - self.len()
87+
}
88+
89+
#[inline]
90+
pub fn len(&self) -> usize {
91+
self.len
92+
}
93+
94+
#[inline]
95+
pub fn is_empty(&self) -> bool {
96+
self.len == 0
97+
}
98+
99+
/// Resets the filled bytes in the buffer
100+
///
101+
/// Note that data is not actually wiped with this method. If that behavior is desired then
102+
/// calling [`Self::consume_filled`] should be preferred.
103+
#[inline]
104+
pub fn clear(&mut self) {
105+
self.head = 0;
106+
self.len = 0;
107+
}
108+
109+
/// Consumes `len` bytes from the head of the buffer
110+
///
111+
/// # Panics
112+
///
113+
/// `len` MUST be less than or equal to [`Self::len`]
114+
#[inline]
115+
pub fn consume(&mut self, len: usize) {
116+
self.preconditions();
117+
118+
assert!(self.len() >= len);
119+
120+
if len >= self.len() {
121+
self.clear();
122+
return;
123+
}
124+
125+
// Wrap the head around the capacity
126+
self.head = deque::wrap(&self.bytes, self.head, len);
127+
self.len -= len;
128+
129+
self.postconditions()
130+
}
131+
132+
/// Returns the filled bytes in the buffer
133+
#[inline]
134+
pub fn filled(&mut self) -> deque::Pair<&mut [u8]> {
135+
self.preconditions();
136+
137+
unsafe {
138+
// SAFETY: cursors guarantee memory is filled
139+
deque::filled(&mut self.bytes, self.head, self.len).assume_init_mut()
140+
}
141+
}
142+
143+
/// Returns and consumes `len` filled bytes in the buffer
144+
///
145+
/// # Panics
146+
///
147+
/// `len` MUST be less than or equal to [`Self::len`]
148+
#[inline]
149+
pub fn consume_filled(&mut self, len: usize) -> deque::Pair<&mut [u8]> {
150+
self.preconditions();
151+
152+
let head = self.head;
153+
154+
self.consume(len);
155+
156+
self.postconditions();
157+
158+
unsafe {
159+
// SAFETY: cursors guarantee memory is filled
160+
deque::filled(&mut self.bytes, head, len).assume_init_mut()
161+
}
162+
}
163+
164+
/// Returns the unfilled bytes in the buffer
165+
///
166+
/// Callers will need to call [`Self::fill`] to indicate any writes that occurred to returned
167+
/// slices.
168+
#[inline]
169+
pub fn unfilled(&mut self) -> deque::Pair<&mut [MaybeUninit<u8>]> {
170+
self.preconditions();
171+
deque::unfilled(&mut self.bytes, self.head, self.len)
172+
}
173+
174+
/// Makes the buffer contiguous and contained in a single slice
175+
#[inline]
176+
pub fn make_contiguous(&mut self) -> &mut [u8] {
177+
self.preconditions();
178+
deque::make_contiguous(&mut self.bytes, &mut self.head, self.len);
179+
self.postconditions();
180+
181+
let (head, tail) = self.filled().into();
182+
debug_assert!(tail.is_empty());
183+
head
184+
}
185+
186+
/// Notifies the buffer that `len` bytes were written to it
187+
///
188+
/// # Safety
189+
///
190+
/// Callers must ensure the filled bytes were actually initialized
191+
#[inline]
192+
pub unsafe fn fill(&mut self, len: usize) -> Result<(), FillError> {
193+
ensure!(self.remaining_capacity() >= len, Err(FillError(())));
194+
195+
self.len += len;
196+
197+
self.postconditions();
198+
199+
Ok(())
200+
}
201+
202+
#[inline(always)]
203+
fn preconditions(&self) {
204+
unsafe {
205+
assume!(deque::invariants(&self.bytes, self.head, self.len));
206+
assume!(self.capacity().is_power_of_two());
207+
}
208+
}
209+
210+
#[inline(always)]
211+
fn postconditions(&self) {
212+
debug_assert!(deque::invariants(&self.bytes, self.head, self.len));
213+
}
214+
}
215+
216+
#[derive(Clone, Copy, Debug, Default)]
217+
pub struct FillError(());
218+
219+
impl fmt::Display for FillError {
220+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
221+
write!(
222+
f,
223+
"the buffer does not have enough capacity for the provided fill amount"
224+
)
225+
}
226+
}
227+
228+
#[cfg(feature = "std")]
229+
impl std::error::Error for FillError {}
230+
231+
#[cfg(feature = "std")]
232+
impl From<FillError> for std::io::Error {
233+
#[inline]
234+
fn from(value: FillError) -> Self {
235+
Self::new(std::io::ErrorKind::InvalidInput, value)
236+
}
237+
}

0 commit comments

Comments
 (0)