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::marker::PhantomData;
29use std::ops::Deref;
30
31use crate::buffers::BufFactory;
32use crate::buffers::DefaultBufFactory;
33
34/// Buffer holding data at a specific offset.
35///
36/// The data is stored in a `Vec<u8>` in such a way that it can be shared
37/// between multiple `RangeBuf` objects.
38///
39/// Each `RangeBuf` will have its own view of that buffer, where the `start`
40/// value indicates the initial offset within the `Vec`, and `len` indicates the
41/// number of bytes, starting from `start` that are included.
42///
43/// In addition, `pos` indicates the current offset within the `Vec`, starting
44/// from the very beginning of the `Vec`.
45///
46/// Finally, `off` is the starting offset for the specific `RangeBuf` within the
47/// stream the buffer belongs to.
48#[derive(Clone, Debug, Default)]
49pub struct RangeBuf<F = DefaultBufFactory>
50where
51 F: BufFactory,
52{
53 /// The internal buffer holding the data.
54 ///
55 /// To avoid needless allocations when a RangeBuf is split, this field
56 /// should be reference-counted so it can be shared between multiple
57 /// RangeBuf objects, and sliced using the `start` and `len` values.
58 pub(crate) data: F::Buf,
59
60 /// The initial offset within the internal buffer.
61 pub(crate) start: usize,
62
63 /// The current offset within the internal buffer.
64 pub(crate) pos: usize,
65
66 /// The number of bytes in the buffer, from the initial offset.
67 pub(crate) len: usize,
68
69 /// The offset of the buffer within a stream.
70 pub(crate) off: u64,
71
72 /// Whether this contains the final byte in the stream.
73 pub(crate) fin: bool,
74
75 _bf: PhantomData<F>,
76}
77
78impl<F: BufFactory> RangeBuf<F>
79where
80 F::Buf: Clone,
81{
82 /// Creates a new `RangeBuf` from the given slice.
83 pub fn from(buf: &[u8], off: u64, fin: bool) -> RangeBuf<F> {
84 Self::from_raw(F::buf_from_slice(buf), off, fin)
85 }
86
87 pub fn from_raw(data: F::Buf, off: u64, fin: bool) -> RangeBuf<F> {
88 RangeBuf {
89 len: data.as_ref().len(),
90 data,
91 start: 0,
92 pos: 0,
93 off,
94 fin,
95 _bf: Default::default(),
96 }
97 }
98
99 /// Returns whether `self` holds the final offset in the stream.
100 pub fn fin(&self) -> bool {
101 self.fin
102 }
103
104 /// Returns the starting offset of `self`.
105 pub fn off(&self) -> u64 {
106 (self.off - self.start as u64) + self.pos as u64
107 }
108
109 /// Returns the final offset of `self`.
110 pub fn max_off(&self) -> u64 {
111 self.off() + self.len() as u64
112 }
113
114 /// Returns the length of `self`.
115 pub fn len(&self) -> usize {
116 self.len - (self.pos - self.start)
117 }
118
119 /// Returns true if `self` has a length of zero bytes.
120 pub fn is_empty(&self) -> bool {
121 self.len() == 0
122 }
123
124 /// Consumes the starting `count` bytes of `self`.
125 pub fn consume(&mut self, count: usize) {
126 self.pos += count;
127 }
128
129 /// Splits the buffer into two at the given index.
130 pub fn split_off(&mut self, at: usize) -> RangeBuf<F>
131 where
132 F::Buf: Clone + AsRef<[u8]>,
133 {
134 assert!(
135 at <= self.len,
136 "`at` split index (is {}) should be <= len (is {})",
137 at,
138 self.len
139 );
140
141 let buf = RangeBuf {
142 data: self.data.clone(),
143 start: self.start + at,
144 pos: cmp::max(self.pos, self.start + at),
145 len: self.len - at,
146 off: self.off + at as u64,
147 _bf: Default::default(),
148 fin: self.fin,
149 };
150
151 self.pos = cmp::min(self.pos, self.start + at);
152 self.len = at;
153 self.fin = false;
154
155 buf
156 }
157}
158
159impl<F: BufFactory> Deref for RangeBuf<F> {
160 type Target = [u8];
161
162 fn deref(&self) -> &[u8] {
163 &self.data.as_ref()[self.pos..self.start + self.len]
164 }
165}
166
167impl<F: BufFactory> Ord for RangeBuf<F> {
168 fn cmp(&self, other: &RangeBuf<F>) -> cmp::Ordering {
169 // Invert ordering to implement min-heap.
170 self.off.cmp(&other.off).reverse()
171 }
172}
173
174impl<F: BufFactory> PartialOrd for RangeBuf<F> {
175 fn partial_cmp(&self, other: &RangeBuf<F>) -> Option<cmp::Ordering> {
176 Some(self.cmp(other))
177 }
178}
179
180impl<F: BufFactory> Eq for RangeBuf<F> {}
181
182impl<F: BufFactory> PartialEq for RangeBuf<F> {
183 fn eq(&self, other: &RangeBuf<F>) -> bool {
184 self.off == other.off
185 }
186}