Skip to main content

o3/buffer/storage/inline/
mod.rs

1use std::{hash, mem};
2
3pub use append::Append;
4
5use crate::{
6    buffer,
7    buffer::{bytes, storage::inline, write, write::consume::Error},
8};
9
10pub const CAPACITY: usize = 24;
11
12mod append;
13
14/// A cleared inline owner with a compile-time remaining write bound.
15pub struct Fill<'a, const LEFT: usize, L = u16> {
16    output: &'a mut [u8; LEFT],
17    len: &'a mut L,
18}
19
20impl<'a, const LEFT: usize, L: crate::buffer::raw::Length> Fill<'a, LEFT, L> {
21    pub fn new(target: &'a mut inline::Bytes<LEFT, L>) -> Self {
22        target.len = L::ZERO;
23        Self {
24            output: &mut target.bytes,
25            len: &mut target.len,
26        }
27    }
28
29    pub fn write<const MAX: usize, const NEXT: usize>(
30        self,
31        source: bytes::Prefix<'_, MAX>,
32    ) -> (Fill<'a, NEXT, L>, &'a mut [u8]) {
33        const { assert!(MAX <= LEFT && NEXT == LEFT - MAX) }
34        let source = source.as_slice();
35        // SAFETY: Prefix bounds input by MAX, and the consuming transition
36        // retains at least LEFT bytes of this owner's disjoint remaining storage.
37        let (copied, output) = unsafe { self.output.split_at_mut_unchecked(source.len()) };
38        inline::Append::new(copied, self.len).write(|output| output.copy_from_slice(source));
39        (
40            Fill {
41                // SAFETY: NEXT <= LEFT - source.len() admits this disjoint initialized suffix.
42                output: unsafe { &mut *output.as_mut_ptr().cast::<[u8; NEXT]>() },
43                len: self.len,
44            },
45            copied,
46        )
47    }
48
49    /// Writes the final bounded source and releases the remaining output borrow.
50    pub fn finish(self, source: bytes::Prefix<'_, LEFT>) {
51        let _ = self.write::<LEFT, 0>(source);
52    }
53}
54
55const _: () = assert!(mem::size_of::<Fill<'_, 284>>() == 2 * mem::size_of::<usize>());
56
57/// Fixed-capacity owned bytes with an integer prefix length.
58#[repr(C)]
59#[derive(Clone, Copy, Debug)]
60pub struct Bytes<const CAP: usize = { CAPACITY }, L = u8> {
61    pub(in crate::buffer::storage::inline) bytes: [u8; CAP],
62    pub(in crate::buffer::storage::inline) len: L,
63}
64
65impl<const CAP: usize, L: crate::buffer::raw::Length> Bytes<CAP, L> {
66    const VALID: () = assert!(CAP <= L::MAX, "inline byte capacity exceeds length field");
67
68    #[must_use]
69    pub const fn new() -> Self {
70        let () = Self::VALID;
71        Self {
72            bytes: [0; CAP],
73            len: L::ZERO,
74        }
75    }
76
77    pub fn from_slice(bytes: &[u8]) -> Result<Self, Error> {
78        let mut inline = Self::new();
79        write::Sink::write_slice(&mut inline, bytes)?;
80        Ok(inline)
81    }
82
83    /// Reserves an exact region or returns its precise capacity shortfall.
84    pub fn try_reserve(&mut self, amount: usize) -> Result<inline::Append<'_, L>, Error> {
85        Error::check(amount, self.available())?;
86        Ok(self.fit(amount))
87    }
88
89    /// Reserves the largest prefix up to `amount` that currently fits.
90    pub fn fit(&mut self, amount: usize) -> inline::Append<'_, L> {
91        let start = self.len();
92        let end = start + amount.min(CAP - start);
93        // SAFETY: the clamped suffix stays within this initialized backing.
94        let output = unsafe { self.bytes.get_unchecked_mut(start..end) };
95        inline::Append::new(output, &mut self.len)
96    }
97
98    /// Replaces the suffix after `start`, admitting every source within `limit`.
99    /// Both bounds are clamped to this owner's initialized length and capacity.
100    /// Rejection leaves the complete backing and initialized length unchanged.
101    pub fn try_replace<const N: usize>(
102        &mut self,
103        start: usize,
104        limit: usize,
105        slices: [&[u8]; N],
106    ) -> Result<(), Error> {
107        let start = start.min(self.len());
108        let end = Error::checked_end(start, limit.min(CAP), &slices)?;
109        // SAFETY: admission bounds every disjoint source within this owner's
110        // backing; only the complete copy publishes the initialized end.
111        unsafe {
112            buffer::raw::SliceExt::copy_to(&slices, self.bytes.as_mut_ptr().add(start));
113        }
114        self.len = L::from_usize(end);
115        Ok(())
116    }
117
118    pub fn truncate(&mut self, len: usize) {
119        if len < self.len() {
120            self.len = L::from_usize(len);
121        }
122    }
123
124    pub fn clear(&mut self) {
125        self.len = L::ZERO;
126    }
127
128    pub fn len(&self) -> usize {
129        self.len.into_usize()
130    }
131
132    pub fn is_empty(&self) -> bool {
133        self.len() == 0
134    }
135
136    pub fn available(&self) -> usize {
137        CAP - self.len()
138    }
139
140    /// Returns the complete initialized backing without changing its prefix.
141    pub fn backing_mut(&mut self) -> &mut [u8; CAP] {
142        &mut self.bytes
143    }
144}
145
146impl<const CAP: usize, L: crate::buffer::raw::Length> Default for Bytes<CAP, L> {
147    fn default() -> Self {
148        Self::new()
149    }
150}
151
152impl<const CAP: usize, L: crate::buffer::raw::Length, const N: usize> From<[u8; N]>
153    for Bytes<CAP, L>
154{
155    fn from(bytes: [u8; N]) -> Self {
156        const { assert!(N <= CAP, "inline array must fit its backing capacity") };
157        Self::from(bytes::Prefix::<CAP>::new(&bytes))
158    }
159}
160
161impl<const CAP: usize, L: crate::buffer::raw::Length> From<bytes::Prefix<'_, CAP>>
162    for Bytes<CAP, L>
163{
164    fn from(source: bytes::Prefix<'_, CAP>) -> Self {
165        let mut prefix = Self::new();
166        let source = source.as_slice();
167        // SAFETY: Prefix bounds the source by CAP and this fresh owner is disjoint.
168        unsafe { buffer::raw::SliceExt::copy_to(source, prefix.bytes.as_mut_ptr()) };
169        prefix.len = L::from_usize(source.len());
170        prefix
171    }
172}
173
174impl<const CAP: usize, L: crate::buffer::raw::Length> PartialEq for Bytes<CAP, L> {
175    fn eq(&self, other: &Self) -> bool {
176        self.as_ref() == other.as_ref()
177    }
178}
179
180impl<const CAP: usize, L: crate::buffer::raw::Length> Eq for Bytes<CAP, L> {}
181
182impl<const CAP: usize, L: crate::buffer::raw::Length> hash::Hash for Bytes<CAP, L> {
183    fn hash<H: hash::Hasher>(&self, state: &mut H) {
184        self.as_ref().hash(state);
185    }
186}
187
188impl<const CAP: usize, L: crate::buffer::raw::Length> AsRef<[u8]> for Bytes<CAP, L> {
189    fn as_ref(&self) -> &[u8] {
190        // SAFETY: construction and every append bound the initialized prefix by CAP.
191        unsafe { self.bytes.get_unchecked(..self.len()) }
192    }
193}
194
195impl<const CAP: usize, L: crate::buffer::raw::Length> AsMut<[u8]> for Bytes<CAP, L> {
196    fn as_mut(&mut self) -> &mut [u8] {
197        let len = self.len();
198        // SAFETY: the exclusive owner retains its initialized prefix bounded by CAP.
199        unsafe { self.bytes.get_unchecked_mut(..len) }
200    }
201}
202
203impl<const CAP: usize, L: crate::buffer::raw::Length> write::Sink for Bytes<CAP, L> {
204    type Error = Error;
205
206    fn write_slice(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
207        self.try_reserve(bytes.len())?
208            .write(|output| output.copy_from_slice(bytes));
209        Ok(())
210    }
211
212    fn write_slices<const N: usize>(&mut self, slices: [&[u8]; N]) -> Result<(), Self::Error> {
213        self.try_replace(self.len(), CAP, slices)
214    }
215}
216
217// SAFETY: inline storage retains its prefix, and its Sink implementation only appends.
218unsafe impl<const CAP: usize, L> buffer::raw::Source for Bytes<CAP, L> where
219    Bytes<CAP, L>: AsRef<[u8]>
220{
221}