quiche/range_buf.rs
1// Copyright (C) 2025, Cloudflare, Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright notice,
9// this list of conditions and the following disclaimer.
10//
11// * Redistributions in binary form must reproduce the above copyright
12// notice, this list of conditions and the following disclaimer in the
13// documentation and/or other materials provided with the distribution.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
16// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
19// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27use std::cmp;
28use std::fmt::Debug;
29use std::marker::PhantomData;
30use std::ops::Deref;
31use std::sync::Arc;
32
33/// Buffer holding data at a specific offset.
34///
35/// The data is stored in a `Vec<u8>` in such a way that it can be shared
36/// between multiple `RangeBuf` objects.
37///
38/// Each `RangeBuf` will have its own view of that buffer, where the `start`
39/// value indicates the initial offset within the `Vec`, and `len` indicates the
40/// number of bytes, starting from `start` that are included.
41///
42/// In addition, `pos` indicates the current offset within the `Vec`, starting
43/// from the very beginning of the `Vec`.
44///
45/// Finally, `off` is the starting offset for the specific `RangeBuf` within the
46/// stream the buffer belongs to.
47#[derive(Clone, Debug, Default)]
48pub struct RangeBuf<F = DefaultBufFactory>
49where
50 F: BufFactory,
51{
52 /// The internal buffer holding the data.
53 ///
54 /// To avoid needless allocations when a RangeBuf is split, this field
55 /// should be reference-counted so it can be shared between multiple
56 /// RangeBuf objects, and sliced using the `start` and `len` values.
57 pub(crate) data: F::Buf,
58
59 /// The initial offset within the internal buffer.
60 pub(crate) start: usize,
61
62 /// The current offset within the internal buffer.
63 pub(crate) pos: usize,
64
65 /// The number of bytes in the buffer, from the initial offset.
66 pub(crate) len: usize,
67
68 /// The offset of the buffer within a stream.
69 pub(crate) off: u64,
70
71 /// Whether this contains the final byte in the stream.
72 pub(crate) fin: bool,
73
74 _bf: PhantomData<F>,
75}
76
77/// A trait for providing internal storage buffers for [`RangeBuf`].
78/// The associated type `Buf` can be any type that dereferences to
79/// a slice, but should be fast to clone, eg. by wrapping it with an
80/// [`Arc`].
81pub trait BufFactory: Clone + Default + Debug {
82 /// The type of the generated buffer.
83 type Buf: Clone + Debug + AsRef<[u8]>;
84
85 /// Generate a new buffer from a given slice, the buffer must contain the
86 /// same data as the original slice.
87 fn buf_from_slice(buf: &[u8]) -> Self::Buf;
88}
89
90/// A trait that enables zero-copy sends to quiche. When buffers produced
91/// by the `BufFactory` implement this trait, quiche and h3 can supply the
92/// raw buffers to be sent, instead of slices that must be copied first.
93pub trait BufSplit {
94 /// Split the buffer at a given point, after the split the old buffer
95 /// must only contain the first `at` bytes, while the newly produced
96 /// buffer must containt the remaining bytes.
97 fn split_at(&mut self, at: usize) -> Self;
98
99 /// Try to prepend a prefix to the buffer, return true if succeeded.
100 fn try_add_prefix(&mut self, _prefix: &[u8]) -> bool {
101 false
102 }
103}
104
105/// The default [`BufFactory`] allocates buffers on the heap on demand.
106#[derive(Debug, Clone, Default)]
107pub struct DefaultBufFactory;
108
109/// The default [`BufFactory::Buf`] is a boxed slice wrapped in an [`Arc`].
110#[derive(Debug, Clone, Default)]
111pub struct DefaultBuf(Arc<Box<[u8]>>);
112
113impl BufFactory for DefaultBufFactory {
114 type Buf = DefaultBuf;
115
116 fn buf_from_slice(buf: &[u8]) -> Self::Buf {
117 DefaultBuf(Arc::new(buf.into()))
118 }
119}
120
121impl AsRef<[u8]> for DefaultBuf {
122 fn as_ref(&self) -> &[u8] {
123 &self.0[..]
124 }
125}
126
127impl<F: BufFactory> RangeBuf<F>
128where
129 F::Buf: Clone,
130{
131 /// Creates a new `RangeBuf` from the given slice.
132 pub fn from(buf: &[u8], off: u64, fin: bool) -> RangeBuf<F> {
133 Self::from_raw(F::buf_from_slice(buf), off, fin)
134 }
135
136 pub fn from_raw(data: F::Buf, off: u64, fin: bool) -> RangeBuf<F> {
137 RangeBuf {
138 len: data.as_ref().len(),
139 data,
140 start: 0,
141 pos: 0,
142 off,
143 fin,
144 _bf: Default::default(),
145 }
146 }
147
148 /// Returns whether `self` holds the final offset in the stream.
149 pub fn fin(&self) -> bool {
150 self.fin
151 }
152
153 /// Returns the starting offset of `self`.
154 pub fn off(&self) -> u64 {
155 (self.off - self.start as u64) + self.pos as u64
156 }
157
158 /// Returns the final offset of `self`.
159 pub fn max_off(&self) -> u64 {
160 self.off() + self.len() as u64
161 }
162
163 /// Returns the length of `self`.
164 pub fn len(&self) -> usize {
165 self.len - (self.pos - self.start)
166 }
167
168 /// Returns true if `self` has a length of zero bytes.
169 pub fn is_empty(&self) -> bool {
170 self.len() == 0
171 }
172
173 /// Consumes the starting `count` bytes of `self`.
174 pub fn consume(&mut self, count: usize) {
175 self.pos += count;
176 }
177
178 /// Splits the buffer into two at the given index.
179 pub fn split_off(&mut self, at: usize) -> RangeBuf<F>
180 where
181 F::Buf: Clone + AsRef<[u8]>,
182 {
183 assert!(
184 at <= self.len,
185 "`at` split index (is {}) should be <= len (is {})",
186 at,
187 self.len
188 );
189
190 let buf = RangeBuf {
191 data: self.data.clone(),
192 start: self.start + at,
193 pos: cmp::max(self.pos, self.start + at),
194 len: self.len - at,
195 off: self.off + at as u64,
196 _bf: Default::default(),
197 fin: self.fin,
198 };
199
200 self.pos = cmp::min(self.pos, self.start + at);
201 self.len = at;
202 self.fin = false;
203
204 buf
205 }
206}
207
208impl<F: BufFactory> Deref for RangeBuf<F> {
209 type Target = [u8];
210
211 fn deref(&self) -> &[u8] {
212 &self.data.as_ref()[self.pos..self.start + self.len]
213 }
214}
215
216impl<F: BufFactory> Ord for RangeBuf<F> {
217 fn cmp(&self, other: &RangeBuf<F>) -> cmp::Ordering {
218 // Invert ordering to implement min-heap.
219 self.off.cmp(&other.off).reverse()
220 }
221}
222
223impl<F: BufFactory> PartialOrd for RangeBuf<F> {
224 fn partial_cmp(&self, other: &RangeBuf<F>) -> Option<cmp::Ordering> {
225 Some(self.cmp(other))
226 }
227}
228
229impl<F: BufFactory> Eq for RangeBuf<F> {}
230
231impl<F: BufFactory> PartialEq for RangeBuf<F> {
232 fn eq(&self, other: &RangeBuf<F>) -> bool {
233 self.off == other.off
234 }
235}