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}