Skip to main content

smol_bytes/
buffer.rs

1#[cfg(any(feature = "alloc", feature = "std"))]
2use core::borrow::Borrow;
3
4use core::{
5  mem::{MaybeUninit, transmute},
6  ops::RangeBounds,
7  ptr::{copy_nonoverlapping, write_bytes},
8  slice::from_raw_parts_mut,
9};
10
11use super::error::*;
12
13mod cmp;
14mod fmt;
15mod from;
16mod io;
17mod iter;
18mod ops;
19
20#[cfg(any(feature = "alloc", feature = "std"))]
21pub(crate) use io::{assert_uint_width, sign_extend};
22
23#[cfg(feature = "arbitrary")]
24mod arbitrary;
25#[cfg(feature = "borsh")]
26mod borsh;
27#[cfg(all(feature = "quickcheck", any(feature = "std", feature = "alloc")))]
28mod quickcheck;
29#[cfg(feature = "serde")]
30mod serde;
31
32#[cfg(feature = "pyo3")]
33mod python;
34
35#[cfg(feature = "wasm")]
36mod wasm;
37
38#[cfg(any(feature = "alloc", feature = "std"))]
39pub use bytes::TryGetError;
40
41/// Number of bytes that can be stored inline.
42pub const INLINE_CAP: usize = InlineSize::MAX as usize;
43
44/// A type used internally to encode inline lengths.
45#[derive(Clone, Copy, Debug, PartialEq, Eq)]
46#[repr(u8)]
47pub(crate) enum InlineSize {
48  _V0 = 0,
49  _V1,
50  _V2,
51  _V3,
52  _V4,
53  _V5,
54  _V6,
55  _V7,
56  _V8,
57  _V9,
58  _V10,
59  _V11,
60  _V12,
61  _V13,
62  _V14,
63  _V15,
64  _V16,
65  _V17,
66  _V18,
67  _V19,
68  _V20,
69  _V21,
70  _V22,
71  _V23,
72  _V24,
73  _V25,
74  _V26,
75  _V27,
76  _V28,
77  _V29,
78  _V30,
79  _V31,
80  _V32,
81  _V33,
82  _V34,
83  _V35,
84  _V36,
85  _V37,
86  _V38,
87  _V39,
88  _V40,
89  _V41,
90  _V42,
91  _V43,
92  _V44,
93  _V45,
94  _V46,
95  _V47,
96  _V48,
97  _V49,
98  _V50,
99  _V51,
100  _V52,
101  _V53,
102  _V54,
103  _V55,
104  _V56,
105  _V57,
106  _V58,
107  _V59,
108  _V60,
109  _V61,
110  _V62,
111}
112
113impl InlineSize {
114  const MAX: u8 = InlineSize::_V62 as u8;
115
116  /// ## Safety
117  ///
118  /// `value` must be less than or equal to [`INLINE_CAP`].
119  #[cfg_attr(not(coverage), inline(always))]
120  pub(crate) const unsafe fn from_u8(value: u8) -> Self {
121    debug_assert!(value <= InlineSize::MAX);
122    // SAFETY: caller guarantees `value <= INLINE_CAP == InlineSize::MAX`,
123    // and every such value is a valid discriminant.
124    unsafe { transmute::<u8, InlineSize>(value) }
125  }
126
127  #[cfg_attr(not(coverage), inline(always))]
128  pub(crate) const fn to_u8(self) -> u8 {
129    self as u8
130  }
131
132  #[cfg_attr(not(coverage), inline(always))]
133  pub(crate) const fn to_usize(self) -> usize {
134    self as usize
135  }
136}
137
138#[doc = "A fixed-size buffer for inline storage."]
139#[doc = ""]
140#[doc = "This type can hold at most `62` bytes on stack without heap allocation."]
141#[cfg_attr(feature = "wasm", doc = "")]
142#[cfg_attr(feature = "wasm", doc = "@example")]
143#[cfg_attr(feature = "wasm", doc = "```typescript")]
144#[cfg_attr(feature = "wasm", doc = "import { Buffer } from 'smol-bytes';")]
145#[cfg_attr(
146  feature = "wasm",
147  doc = "const buf = Buffer.fromBytes(new Uint8Array([1, 2, 3]));"
148)]
149#[cfg_attr(feature = "wasm", doc = "console.log(buf.len()); // 3")]
150#[cfg_attr(feature = "wasm", doc = "```")]
151#[derive(Clone, Copy)]
152#[cfg_attr(feature = "pyo3", ::pyo3::prelude::pyclass(skip_from_py_object))]
153#[cfg_attr(feature = "wasm", wasm_bindgen::prelude::wasm_bindgen)]
154pub struct Buffer {
155  // Invariant: 0 <= cur <= end <= INLINE_CAP, and buf[0..end] is initialized.
156  // The absolute write cursor. Public lengths are always `end - cur`.
157  end: InlineSize,
158  // The read cursor
159  cur: InlineSize,
160  buf: [MaybeUninit<u8>; INLINE_CAP],
161}
162
163impl Default for Buffer {
164  #[cfg_attr(not(coverage), inline(always))]
165  fn default() -> Self {
166    Self::new()
167  }
168}
169
170impl Buffer {
171  /// Creates a new, empty `Buffer`.
172  ///
173  /// ## Examples
174  ///
175  /// ```
176  /// use smol_bytes::Buffer;
177  ///
178  /// let buf = Buffer::new();
179  /// ```
180  #[cfg_attr(not(coverage), inline(always))]
181  pub const fn new() -> Self {
182    Self {
183      end: InlineSize::_V0,
184      cur: InlineSize::_V0,
185      buf: [const { MaybeUninit::uninit() }; INLINE_CAP],
186    }
187  }
188
189  /// Creates a new `Buffer` with the specified length, filled with zeroes.
190  ///
191  /// ## Safety
192  /// - `len` must be less than or equal to [`INLINE_CAP`].
193  #[cfg(any(feature = "alloc", feature = "std"))]
194  #[cfg_attr(not(coverage), inline(always))]
195  pub(crate) const unsafe fn zeroed(len: usize) -> Self {
196    let mut storage = [const { MaybeUninit::uninit() }; INLINE_CAP];
197    // SAFETY: caller guarantees `len <= INLINE_CAP`, so writing `len`
198    // zero bytes stays within the storage array.
199    unsafe {
200      core::ptr::write_bytes(storage.as_mut_ptr(), 0, len);
201    }
202    Self {
203      cur: InlineSize::_V0,
204      // SAFETY: len is guaranteed to be less than or equal to INLINE_CAP
205      end: unsafe { InlineSize::from_u8(len as u8) },
206      buf: storage,
207    }
208  }
209
210  /// Creates a new `Buffer` from the given array and length.
211  ///
212  /// ## Safety
213  /// - `len` must be less than or equal to [`INLINE_CAP`].
214  #[cfg_attr(not(coverage), inline(always))]
215  #[allow(unused)]
216  pub(crate) const unsafe fn from_array(buf: [u8; INLINE_CAP], len: usize) -> Self {
217    Self {
218      cur: InlineSize::_V0,
219      // SAFETY: len is guaranteed to be less than or equal to INLINE_CAP
220      end: unsafe { InlineSize::from_u8(len as u8) },
221      // SAFETY: all bytes are initialized
222      buf: unsafe { transmute::<[u8; INLINE_CAP], [MaybeUninit<u8>; INLINE_CAP]>(buf) },
223    }
224  }
225
226  /// Creates a new `Buffer` by copying from the given slice.
227  ///
228  /// ## Safety
229  /// - the length of `src` must be less than or equal to [`INLINE_CAP`].
230  #[cfg_attr(not(coverage), inline(always))]
231  pub const unsafe fn copy_from_slice(src: &[u8]) -> Self {
232    let len = src.len();
233    let mut storage = [const { MaybeUninit::uninit() }; INLINE_CAP];
234
235    // SAFETY: caller guarantees `len <= INLINE_CAP`, matching the size
236    // of `storage`; `src` and `storage` do not overlap.
237    unsafe {
238      copy_nonoverlapping(src.as_ptr(), storage.as_mut_ptr() as _, len);
239    }
240
241    Self {
242      // SAFETY: caller guarantees that `len` is less than or equal to `INLINE_CAP`.
243      end: unsafe { InlineSize::from_u8(len as u8) },
244      cur: InlineSize::_V0,
245      buf: storage,
246    }
247  }
248
249  /// Returns the number of bytes between the current position and the end of
250  /// the buffer.
251  ///
252  /// This value is equal to the length of the slice returned
253  /// by [`as_slice()`](Self::as_slice).
254  ///
255  /// # Examples
256  ///
257  /// ```
258  /// use smol_bytes::Buffer;
259  ///
260  /// let mut buf = Buffer::try_from(*b"hello world").unwrap();
261  ///
262  /// assert_eq!(buf.remaining(), 11);
263  ///
264  /// buf.get_u8();
265  ///
266  /// assert_eq!(buf.remaining(), 10);
267  /// ```
268  ///
269  /// # Implementer notes
270  ///
271  /// Implementations of `remaining` should ensure that the return value does
272  /// not change unless a call is made to `advance` or any other function that
273  /// is documented to change the `Buf`'s current position.
274  #[cfg_attr(not(coverage), inline(always))]
275  pub const fn remaining(&self) -> usize {
276    self.end.to_usize() - self.cur.to_usize()
277  }
278
279  /// Returns the number of visible bytes contained in this `Buffer`.
280  ///
281  /// ## Example
282  ///
283  /// ```rust
284  /// use smol_bytes::Buffer;
285  ///
286  /// let bytes = Buffer::new();
287  /// assert_eq!(bytes.len(), 0);
288  /// ```
289  #[cfg_attr(not(coverage), inline(always))]
290  pub const fn len(&self) -> usize {
291    self.remaining()
292  }
293
294  /// Returns `true` if the `Buffer` has no visible bytes.
295  ///
296  /// ## Example
297  ///
298  /// ```rust
299  /// use smol_bytes::BytesMut;
300  ///
301  /// let bytes = BytesMut::new();
302  /// assert!(bytes.is_empty());
303  /// ```
304  #[cfg_attr(not(coverage), inline(always))]
305  pub const fn is_empty(&self) -> bool {
306    self.len() == 0
307  }
308
309  /// Returns the number of bytes that can be written from the current
310  /// position until the end of the buffer is reached.
311  ///
312  /// This value is equal to the length of the slice returned
313  /// by `chunk_mut()`.
314  ///
315  /// ## Examples
316  ///
317  /// ```
318  /// use smol_bytes::{Buffer, BufMut};
319  ///
320  /// let mut dst = Buffer::new();
321  ///
322  /// let original_remaining = dst.remaining_mut();
323  /// dst.put(&b"hello"[..]);
324  ///
325  /// assert_eq!(original_remaining - 5, dst.remaining_mut());
326  /// ```
327  #[cfg_attr(not(coverage), inline(always))]
328  pub const fn remaining_mut(&self) -> usize {
329    INLINE_CAP - self.end.to_usize()
330  }
331
332  /// Reclaims consumed prefix space when doing so provides `additional`
333  /// bytes of writable tail without allocating.
334  #[cfg(any(feature = "alloc", feature = "std"))]
335  #[cfg_attr(not(coverage), inline(always))]
336  pub(crate) fn try_reclaim(&mut self, additional: usize) -> bool {
337    if additional <= self.remaining_mut() {
338      return true;
339    }
340
341    let len = self.len();
342    if additional > INLINE_CAP - len {
343      return false;
344    }
345
346    let cur = self.cur.to_usize();
347    if cur != 0 {
348      // `copy_within` is overlap-safe; the invariant keeps `cur..end` within
349      // the initialized prefix and its length is exactly `len`.
350      self.buf.copy_within(cur..self.end.to_usize(), 0);
351    }
352
353    self.cur = InlineSize::_V0;
354    // SAFETY: `len <= INLINE_CAP`, so it is a valid `InlineSize`; the copy
355    // above established that `buf[..len]` is initialized.
356    self.end = unsafe { InlineSize::from_u8(len as u8) };
357    true
358  }
359
360  /// Sets the visible length of the buffer.
361  ///
362  /// This will explicitly set the size of the buffer without actually
363  /// modifying the data, so it is up to the caller to ensure that the data
364  /// has been initialized.
365  ///
366  /// ## Safety
367  ///
368  /// - `len` must not exceed [`capacity`](Self::capacity).
369  /// - Every byte in the current view's `0..len` range must be initialized.
370  ///
371  /// ## Examples
372  ///
373  /// ```
374  /// use smol_bytes::Buffer;
375  ///
376  /// let mut b = Buffer::try_from(&b"hello world"[..]).unwrap();
377  ///
378  /// unsafe {
379  ///     b.set_len(5);
380  /// }
381  ///
382  /// assert_eq!(&b[..], b"hello");
383  ///
384  /// unsafe {
385  ///     b.set_len(11);
386  /// }
387  ///
388  /// assert_eq!(&b[..], b"hello world");
389  /// ```
390  #[allow(clippy::missing_safety_doc)]
391  #[cfg_attr(not(coverage), inline(always))]
392  pub const unsafe fn set_len(&mut self, len: usize) {
393    debug_assert!(len <= self.capacity(), "set_len out of bounds");
394    let end = self.cur.to_usize() + len;
395    // SAFETY: the caller guarantees `len <= self.capacity()`, so
396    // `cur + len <= INLINE_CAP` and is a valid `InlineSize` discriminant.
397    self.end = unsafe { InlineSize::from_u8(end as u8) };
398  }
399
400  /// Advance the internal cursor of the `Buffer`
401  ///
402  /// The next call to `as_slice()` will return a slice starting `cnt` bytes
403  /// further into the underlying buffer.
404  ///
405  /// ## Examples
406  ///
407  /// ```
408  /// use smol_bytes::{Buffer, INLINE_CAP};
409  ///
410  /// let mut buf = Buffer::try_from(&b"hello world"[..]).unwrap();
411  ///
412  /// assert_eq!(buf.as_slice(), &b"hello world"[..]);
413  ///
414  /// buf.advance(6);
415  ///
416  /// assert_eq!(buf.as_slice(), &b"world"[..]);
417  ///
418  /// // advancing will also reduce capacity
419  /// assert_eq!(buf.capacity(), INLINE_CAP - 6);
420  /// ```
421  ///
422  /// ## Panics
423  ///
424  /// This function panics if `cnt > self.remaining()`.
425  #[cfg_attr(not(coverage), inline(always))]
426  pub fn advance(&mut self, requested: usize) {
427    if let Err(err) = self.try_advance(requested) {
428      panic_advance(err.available, err.requested)
429    }
430  }
431
432  /// Tries to advance the internal cursor of the `Buffer`.
433  ///
434  /// Returns `Err(OutOfBounds)` if `requested` exceeds the remaining length.
435  #[cfg_attr(not(coverage), inline(always))]
436  pub fn try_advance(&mut self, requested: usize) -> Result<(), OutOfBounds> {
437    if requested == 0 {
438      return Ok(());
439    }
440
441    let available = self.remaining();
442    if available < requested {
443      return Err(OutOfBounds::new(requested, available));
444    }
445    // SAFETY: `requested <= remaining == end - cur`, so the new cursor is
446    // at most `end` and therefore at most `INLINE_CAP`.
447    self.cur = unsafe { InlineSize::from_u8(self.cur.to_u8() + requested as u8) };
448    Ok(())
449  }
450
451  /// Advance the internal write cursor of the `Buffer`
452  ///
453  /// The next call to [`spare_capacity_mut`](Self::spare_capacity_mut) will return a slice starting `cnt` bytes
454  /// further into the underlying buffer.
455  ///
456  /// ## Safety
457  ///
458  /// The caller must ensure that the next `cnt` bytes of `chunk` are
459  /// initialized.
460  ///
461  /// ## Examples
462  ///
463  /// ```
464  /// use smol_bytes::Buffer;
465  ///
466  /// let mut buf = Buffer::new();
467  ///
468  /// // Write some data
469  /// unsafe {
470  ///   let tmp = buf.spare_capacity_mut();
471  ///   core::ptr::copy(b"he".as_ptr(), tmp.as_mut_ptr() as _, 2);
472  ///   buf.advance_mut(2);
473  /// }
474  ///
475  /// // write more bytes
476  /// unsafe {
477  ///   let tmp = buf.spare_capacity_mut();
478  ///   core::ptr::copy(b"llo".as_ptr(), tmp.as_mut_ptr() as _, 3);
479  ///   buf.advance_mut(3);
480  /// }
481  ///
482  /// assert_eq!(5, buf.len());
483  /// assert_eq!(buf, "hello".as_bytes());
484  /// ```
485  ///
486  /// ## Panics
487  ///
488  /// This function panic if `requested > self.remaining_mut()`.
489  pub unsafe fn advance_mut(&mut self, requested: usize) {
490    let available = self.remaining_mut();
491    if requested > available {
492      panic_advance(available, requested)
493    }
494
495    // SAFETY: `requested <= remaining_mut == INLINE_CAP - end`, so the new
496    // absolute end is a valid `InlineSize` and the caller initialized the
497    // bytes being exposed, as required by `advance_mut`.
498    self.end = unsafe { InlineSize::from_u8(self.end.to_u8() + requested as u8) };
499  }
500
501  /// Shortens the buffer, keeping the first len bytes and dropping the rest.
502  ///
503  /// If len is greater than the buffer’s current length, this has no effect.
504  ///
505  /// Existing underlying capacity is preserved.
506  ///
507  /// ## Example
508  ///
509  /// ```rust
510  /// use smol_bytes::Buffer;
511  ///
512  /// let mut bytes = Buffer::try_from(&b"hello world"[..]).unwrap();
513  ///
514  /// bytes.truncate(5);
515  /// assert_eq!(bytes.as_mut_slice(), b"hello");
516  /// ```
517  #[cfg_attr(not(coverage), inline(always))]
518  pub const fn truncate(&mut self, new_len: usize) {
519    if new_len >= self.len() {
520      return;
521    }
522
523    let new_end = self.cur.to_usize() + new_len;
524    // SAFETY: `new_len < self.len() == end - cur`, so `new_end < end` and
525    // remains a valid `InlineSize`. No bytes are moved or newly exposed.
526    self.end = unsafe { InlineSize::from_u8(new_end as u8) };
527  }
528
529  /// Splits the buffer into two at the given index.
530  ///
531  /// Afterwards `self` contains elements `[0, at)`, and the returned `Buffer`
532  /// contains elements `[at, len)`.
533  ///
534  /// This operation copies the tail into a new `Buffer`.
535  ///
536  /// ## Example
537  ///
538  /// ```rust
539  /// use smol_bytes::Buffer;
540  ///
541  /// let mut a = Buffer::try_from(&b"hello world"[..]).unwrap();
542  /// let b = a.split_off(5);
543  /// assert_eq!(a.as_slice(), b"hello");
544  /// assert_eq!(b.as_slice(), b" world");
545  /// ```
546  ///
547  /// ## Panics
548  ///
549  /// Panics if `at > len`.
550  #[must_use = "consider Buffer::truncate if you don't need the other half"]
551  pub fn split_off(&mut self, at: usize) -> Self {
552    self
553      .try_split_off(at)
554      .unwrap_or_else(|_| panic!("split_off out of bounds: {} > {}", at, self.remaining()))
555  }
556
557  /// Splits the buffer into two at the given index.
558  ///
559  /// Afterwards `self` contains elements `[at, len)`, and the returned `Buffer`
560  /// contains elements `[0, at)`.
561  ///
562  /// This operation copies the head into a new `Buffer`.
563  ///
564  /// ## Example
565  ///
566  /// ```rust
567  /// use smol_bytes::Buffer;
568  ///
569  /// let mut a = Buffer::try_from(&b"hello world"[..]).unwrap();
570  /// let b = a.split_to(5);
571  /// assert_eq!(b.as_slice(), b"hello");
572  /// assert_eq!(a.as_slice(), b" world");
573  /// ```
574  ///
575  /// ## Panics
576  ///
577  /// Panics if `at > len`.
578  #[must_use = "consider Buffer::advance if you don't need the other half"]
579  pub fn split_to(&mut self, at: usize) -> Self {
580    self
581      .try_split_to(at)
582      .unwrap_or_else(|_| panic!("split_to out of bounds: {} > {}", at, self.remaining()))
583  }
584
585  /// Tries to split the buffer into two at the given index.
586  ///
587  /// Afterwards `self` contains elements `[0, at)`, and the returned `Buffer`
588  /// contains elements `[at, len)`.
589  ///
590  /// Returns `Err(OutOfBounds)` if `at > remaining()`.
591  ///
592  /// ## Example
593  ///
594  /// ```rust
595  /// use smol_bytes::Buffer;
596  ///
597  /// let mut a = Buffer::try_from(&b"hello world"[..]).unwrap();
598  /// let b = a.try_split_off(5).unwrap();
599  /// assert_eq!(a.as_slice(), b"hello");
600  /// assert_eq!(b.as_slice(), b" world");
601  /// ```
602  #[must_use = "consider Buffer::truncate if you don't need the other half"]
603  pub const fn try_split_off(&mut self, at: usize) -> Result<Self, OutOfBounds> {
604    let len = self.remaining();
605    if at > len {
606      return Err(OutOfBounds::new(at, len));
607    }
608
609    let tail_len = len - at;
610    // SAFETY: `at <= len` proves the source range `at..len` is initialized;
611    // `tail_len <= INLINE_CAP` keeps the destination in `new_buf`, and the
612    // distinct buffers cannot overlap.
613    let tail = unsafe {
614      let mut new_buf = Self::new();
615      if tail_len > 0 {
616        let src = self.as_slice().as_ptr().add(at);
617        copy_nonoverlapping(src, new_buf.buf.as_mut_ptr() as *mut u8, tail_len);
618        new_buf.end = InlineSize::from_u8(tail_len as u8);
619      }
620      new_buf
621    };
622
623    self.truncate(at);
624    Ok(tail)
625  }
626
627  /// Tries to split the buffer into two at the given index.
628  ///
629  /// Afterwards `self` contains elements `[at, len)`, and the returned `Buffer`
630  /// contains elements `[0, at)`.
631  ///
632  /// Returns `Err(OutOfBounds)` if `at > remaining()`.
633  ///
634  /// ## Example
635  ///
636  /// ```rust
637  /// use smol_bytes::Buffer;
638  ///
639  /// let mut a = Buffer::try_from(&b"hello world"[..]).unwrap();
640  /// let b = a.try_split_to(5).unwrap();
641  /// assert_eq!(b.as_slice(), b"hello");
642  /// assert_eq!(a.as_slice(), b" world");
643  /// ```
644  #[must_use = "consider Buffer::advance if you don't need the other half"]
645  pub const fn try_split_to(&mut self, at: usize) -> Result<Self, OutOfBounds> {
646    let len = self.remaining();
647    if at > len {
648      return Err(OutOfBounds::new(at, len));
649    }
650
651    // SAFETY: `at <= len <= INLINE_CAP` proves the source prefix is
652    // initialized and the destination fits; the distinct buffers cannot
653    // overlap.
654    let head = unsafe {
655      let mut new_buf = Self::new();
656      if at > 0 {
657        let src = self.as_slice().as_ptr();
658        copy_nonoverlapping(src, new_buf.buf.as_mut_ptr() as *mut u8, at);
659        new_buf.end = InlineSize::from_u8(at as u8);
660      }
661      new_buf
662    };
663
664    // SAFETY: `at <= remaining == end - cur`, so the new cursor is at most
665    // `end` and remains a valid `InlineSize`.
666    self.cur = unsafe { InlineSize::from_u8(self.cur.to_u8() + at as u8) };
667    Ok(head)
668  }
669
670  /// Creates a new buffer containing a copy of the specified range.
671  ///
672  /// ## Example
673  ///
674  /// ```rust
675  /// use smol_bytes::Buffer;
676  ///
677  /// let buf = Buffer::try_from(&b"hello world"[..]).unwrap();
678  /// let slice = buf.slice(0..5);
679  /// assert_eq!(slice.as_slice(), b"hello");
680  /// ```
681  ///
682  /// ## Panics
683  ///
684  /// Panics if the range is out of bounds.
685  pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
686    self.try_slice(range).unwrap_or_else(|e| panic!("{e}"))
687  }
688
689  /// Tries to create a new buffer containing a copy of the specified range.
690  ///
691  /// Returns `Err(OutOfBounds)` if the range is out of bounds or the slice is too large.
692  ///
693  /// ## Example
694  ///
695  /// ```rust
696  /// use smol_bytes::Buffer;
697  ///
698  /// let buf = Buffer::try_from(&b"hello world"[..]).unwrap();
699  /// let slice = buf.try_slice(0..5).unwrap();
700  /// assert_eq!(slice.as_slice(), b"hello");
701  /// ```
702  pub fn try_slice(&self, range: impl RangeBounds<usize>) -> Result<Self, RangeOutOfBounds> {
703    let len = self.len();
704    let (begin, end) = normalize_range(range, len)?;
705
706    if begin == end {
707      return Ok(Self::new());
708    }
709
710    // SAFETY: `normalize_range` proves `begin <= end <= self.len()`, so the
711    // subslice is initialized and its length is at most `INLINE_CAP`.
712    Ok(unsafe { Self::copy_from_slice(&self.as_slice()[begin..end]) })
713  }
714
715  /// Resizes the buffer to the specified length, filling with zeros if expanding.
716  ///
717  /// ## Example
718  ///
719  /// ```rust
720  /// use smol_bytes::Buffer;
721  ///
722  /// let mut buf = Buffer::try_from(&b"hello"[..]).unwrap();
723  /// buf.resize(8);
724  /// assert_eq!(buf.as_slice(), b"hello\0\0\0");
725  ///
726  /// buf.resize(3);
727  /// assert_eq!(buf.as_slice(), b"hel");
728  /// ```
729  ///
730  /// ## Panics
731  ///
732  /// Panics if the new length exceeds capacity.
733  pub fn resize(&mut self, new_len: usize) {
734    let current_len = self.remaining();
735
736    if new_len == current_len {
737      return;
738    }
739
740    if new_len < current_len {
741      self.truncate(new_len);
742      return;
743    }
744
745    // Expanding
746    let additional = new_len - current_len;
747    assert!(
748      self.remaining_mut() >= additional,
749      "resize exceeds capacity: {} + {} > {}",
750      current_len,
751      additional,
752      self.capacity()
753    );
754
755    self.put_bytes(0, additional);
756  }
757
758  /// Tries to resize the buffer to the specified length, filling with zeros if expanding.
759  ///
760  /// Returns `Err(OutOfBounds)` if the new length exceeds capacity.
761  ///
762  /// ## Example
763  ///
764  /// ```rust
765  /// use smol_bytes::Buffer;
766  ///
767  /// let mut buf = Buffer::try_from(&b"hello"[..]).unwrap();
768  /// assert!(buf.try_resize(8).is_ok());
769  /// assert_eq!(buf.as_slice(), b"hello\0\0\0");
770  ///
771  /// assert!(buf.try_resize(3).is_ok());
772  /// assert_eq!(buf.as_slice(), b"hel");
773  /// ```
774  pub const fn try_resize(&mut self, new_len: usize) -> Result<(), OutOfBounds> {
775    let current_len = self.remaining();
776
777    if new_len == current_len {
778      return Ok(());
779    }
780
781    if new_len < current_len {
782      self.truncate(new_len);
783      return Ok(());
784    }
785
786    // Expanding
787    let additional = new_len - current_len;
788    if self.remaining_mut() < additional {
789      return Err(OutOfBounds::new(new_len, self.capacity()));
790    }
791
792    match self.try_put_bytes(0, additional) {
793      Ok(()) => Ok(()),
794      Err(_) => {
795        // The identical capacity check above makes this branch unreachable;
796        // retain a defensive error instead of relying on unchecked state.
797        Err(OutOfBounds::new(new_len, self.capacity()))
798      }
799    }
800  }
801
802  /// Clears the buffer, removing all data. Existing capacity is preserved.
803  ///
804  /// ## Example
805  ///
806  /// ```rust
807  /// use smol_bytes::Buffer;
808  ///
809  /// let mut bytes = Buffer::try_from(&b"hello world"[..]).unwrap();
810  /// bytes.clear();
811  /// assert_eq!(bytes.len(), 0);
812  /// ```
813  #[cfg_attr(not(coverage), inline(always))]
814  pub const fn clear(&mut self) {
815    self.end = InlineSize::_V0;
816    self.cur = InlineSize::_V0;
817  }
818
819  /// Returns the remaining spare capacity of the buffer as a slice of [`MaybeUninit<u8>`].
820  ///
821  /// The returned slice can be used to fill the buffer with data (e.g. by reading from a file) before marking the data as initialized using the [`set_len`](Self::set_len) method.
822  ///
823  /// ## Example
824  ///
825  /// ```
826  /// use smol_bytes::{Buffer, INLINE_CAP};
827  ///
828  /// let mut buf = Buffer::new();
829  ///
830  /// // Fill in the first 3 elements.
831  /// let uninit = buf.spare_capacity_mut();
832  /// uninit[0].write(0);
833  /// uninit[1].write(1);
834  /// uninit[2].write(2);
835  ///
836  /// // Mark the first 3 bytes of the buffer as being initialized.
837  /// unsafe {
838  ///   buf.set_len(3);
839  /// }
840  ///
841  /// assert_eq!(buf.as_slice(), &[0, 1, 2]);
842  /// ```
843  #[cfg_attr(not(coverage), inline(always))]
844  pub const fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
845    let end = self.end.to_usize();
846    // SAFETY: the invariant guarantees `end <= INLINE_CAP`; `buf.add(end)`
847    // starts the uninitialized tail and the returned length stays in `buf`.
848    unsafe { from_raw_parts_mut(self.buf.as_mut_ptr().add(end), INLINE_CAP - end) }
849  }
850
851  /// Returns the capacity of the buffer.
852  ///
853  /// The capacity is not always equal to [`INLINE_CAP`], as the [`advance`](Self::advance) method
854  /// may move the underlying cursor forward, reducing the available capacity.
855  #[cfg_attr(not(coverage), inline(always))]
856  pub const fn capacity(&self) -> usize {
857    INLINE_CAP - self.cur.to_usize()
858  }
859
860  /// Returns the initialized portion of the buffer as a slice.
861  ///
862  /// This will include all bytes from the start of the buffer up to the current length.
863  #[cfg_attr(not(coverage), inline(always))]
864  pub const fn as_slice(&self) -> &[u8] {
865    let ptr = self.buf.as_ptr() as *const u8;
866    let remaining = self.remaining();
867    // SAFETY: the invariant guarantees `buf[..end]` is initialized and
868    // `cur + remaining == end <= INLINE_CAP`.
869    unsafe { core::slice::from_raw_parts(ptr.add(self.cur.to_usize()), remaining) }
870  }
871
872  /// Returns the mutable initialized portion of the buffer as a mutable slice.
873  ///
874  /// This will include all bytes from the start of the buffer up to the current length.
875  #[cfg_attr(not(coverage), inline(always))]
876  pub const fn as_mut_slice(&mut self) -> &mut [u8] {
877    let ptr = self.buf.as_mut_ptr() as *mut u8;
878    let remaining = Self::remaining(self);
879    // SAFETY: the invariant guarantees `buf[..end]` is initialized and this
880    // exclusive borrow covers exactly `cur..end` within the backing array.
881    unsafe { core::slice::from_raw_parts_mut(ptr.add(self.cur.to_usize()), remaining) }
882  }
883
884  /// Transfer bytes into `self` from `src` and advance the cursor by the
885  /// number of bytes written.
886  ///
887  /// `self` must have enough remaining capacity to contain all of `src`.
888  ///
889  /// ```
890  /// use smol_bytes::{Buffer, INLINE_CAP};
891  ///
892  /// let mut dst = Buffer::new();
893  ///
894  /// {
895  ///     dst.put_slice(b"hello");
896  ///     assert_eq!(INLINE_CAP - 5, dst.remaining_mut());
897  /// }
898  ///
899  /// assert_eq!(dst, "hello");
900  /// ```
901  #[inline]
902  pub fn put_slice(&mut self, src: &[u8]) {
903    self
904      .try_put_slice(src)
905      .unwrap_or_else(|e| panic_advance(e.available, e.requested))
906  }
907
908  /// Try to transfer bytes into `self` from `src` and advance the cursor by the
909  /// number of bytes written.
910  ///
911  /// `self` must have enough remaining capacity to contain all of `src`.
912  ///
913  /// ```
914  /// use smol_bytes::{Buffer, INLINE_CAP};
915  ///
916  /// let mut dst = Buffer::new();
917  ///
918  /// {
919  ///     dst.try_put_slice(b"hello").unwrap();
920  ///     assert_eq!(INLINE_CAP - 5, dst.remaining_mut());
921  /// }
922  ///
923  /// assert_eq!("hello", &dst);
924  /// ```
925  #[inline]
926  pub const fn try_put_slice(&mut self, src: &[u8]) -> Result<(), TryPutError> {
927    let available = self.remaining_mut();
928    let requested = src.len();
929
930    if requested > available {
931      return Err(TryPutError {
932        requested,
933        available,
934      });
935    }
936
937    let slen = self.end.to_usize();
938    // SAFETY: `requested <= remaining_mut` proves `slen + requested <=
939    // INLINE_CAP`; `src` is initialized and cannot overlap this exclusive
940    // buffer borrow.
941    unsafe {
942      copy_nonoverlapping(
943        src.as_ptr(),
944        self.buf.as_mut_ptr().add(slen) as _,
945        requested,
946      );
947    }
948    // SAFETY: the capacity check above proves the new absolute end is at most
949    // `INLINE_CAP`, and the copy initialized every newly exposed byte.
950    self.end = unsafe { InlineSize::from_u8(slen as u8 + requested as u8) };
951    Ok(())
952  }
953
954  /// Put `cnt` bytes `val` into `self`.
955  ///
956  /// Logically equivalent to calling `self.put_u8(val)` `cnt` times, but may work faster.
957  ///
958  /// `self` must have at least `cnt` remaining capacity.
959  ///
960  /// ```
961  /// use smol_bytes::{Buffer, INLINE_CAP};
962  ///
963  /// let mut dst = Buffer::new();
964  ///
965  /// {
966  ///     dst.put_bytes(b'a', 4);
967  ///     assert_eq!(INLINE_CAP - 4, dst.remaining_mut());
968  /// }
969  ///
970  /// assert_eq!("aaaa", &dst);
971  /// ```
972  ///
973  /// ## Panics
974  ///
975  /// This function panics if there is not enough remaining capacity in
976  /// `self`.
977  #[inline]
978  pub fn put_bytes(&mut self, val: u8, cnt: usize) {
979    self
980      .try_put_bytes(val, cnt)
981      .unwrap_or_else(|e| panic_advance(e.available, e.requested))
982  }
983
984  /// Try to put `cnt` bytes `val` into `self`.
985  ///
986  /// Logically equivalent to calling `self.put_u8(val)` `cnt` times, but may work faster.
987  ///
988  /// `self` must have at least `cnt` remaining capacity.
989  ///
990  /// ```
991  /// use smol_bytes::{Buffer, INLINE_CAP};
992  ///
993  /// let mut dst = Buffer::new();
994  ///
995  /// {
996  ///     dst.try_put_bytes(b'a', 4).unwrap();
997  ///     assert_eq!(INLINE_CAP - 4, dst.remaining_mut());
998  /// }
999  ///
1000  /// assert_eq!("aaaa".as_bytes(), &dst);
1001  /// ```
1002  #[inline]
1003  pub const fn try_put_bytes(&mut self, val: u8, cnt: usize) -> Result<(), TryPutError> {
1004    if cnt == 0 {
1005      return Ok(());
1006    }
1007
1008    let available = self.remaining_mut();
1009    if available < cnt {
1010      return Err(TryPutError {
1011        requested: cnt,
1012        available,
1013      });
1014    }
1015
1016    // SAFETY: `cnt <= remaining_mut` proves `end + cnt <= INLINE_CAP`; the
1017    // write initializes exactly the bytes that the new end exposes.
1018    unsafe {
1019      write_bytes(self.buf.as_mut_ptr().add(self.end.to_usize()), val, cnt);
1020    }
1021    // SAFETY: the capacity check above proves the new absolute end is a valid
1022    // `InlineSize`, and `write_bytes` initialized the extended region.
1023    self.end = unsafe { InlineSize::from_u8(self.end.to_u8() + cnt as u8) };
1024    Ok(())
1025  }
1026
1027  /// Put `cnt` bytes `val` into `self`.
1028  ///
1029  /// Logically equivalent to calling `self.put_u8(val)` `cnt` times, but may work faster.
1030  ///
1031  /// `self` must have at least `cnt` remaining capacity.
1032  ///
1033  /// ```
1034  /// use smol_bytes::{Buffer, INLINE_CAP};
1035  ///
1036  /// let mut dst = Buffer::new();
1037  ///
1038  /// {
1039  ///     dst.put_u8(b'a');
1040  ///     assert_eq!(INLINE_CAP - 1, dst.remaining_mut());
1041  /// }
1042  ///
1043  /// assert_eq!("a", &dst);
1044  /// ```
1045  ///
1046  /// ## Panics
1047  ///
1048  /// This function panics if there is not enough remaining capacity in
1049  /// `self`.
1050  #[inline]
1051  pub fn put_u8(&mut self, val: u8) {
1052    self
1053      .try_put_u8(val)
1054      .unwrap_or_else(|e| panic_advance(e.available, e.requested))
1055  }
1056
1057  /// Try to put `cnt` bytes `val` into `self`.
1058  ///
1059  /// Logically equivalent to calling `self.put_u8(val)` `cnt` times, but may work faster.
1060  ///
1061  /// `self` must have at least `cnt` remaining capacity.
1062  ///
1063  /// ```
1064  /// use smol_bytes::{Buffer, INLINE_CAP};
1065  ///
1066  /// let mut dst = Buffer::new();
1067  ///
1068  /// {
1069  ///     dst.try_put_u8(b'a').unwrap();
1070  ///     assert_eq!(INLINE_CAP - 1, dst.remaining_mut());
1071  /// }
1072  ///
1073  /// assert_eq!("a".as_bytes(), &dst);
1074  /// ```
1075  ///
1076  /// ## Panics
1077  ///
1078  /// This function panics if there is not enough remaining capacity in
1079  /// `self`.
1080  #[inline]
1081  pub const fn try_put_u8(&mut self, val: u8) -> Result<(), TryPutError> {
1082    let available = self.remaining_mut();
1083    if available < 1 {
1084      return Err(TryPutError {
1085        requested: 1,
1086        available,
1087      });
1088    }
1089
1090    self.buf[self.end.to_usize()].write(val);
1091    // SAFETY: `remaining_mut >= 1` proves `end + 1 <= INLINE_CAP`, and the
1092    // preceding write initialized the byte being exposed.
1093    self.end = unsafe { InlineSize::from_u8(self.end.to_u8() + 1) };
1094    Ok(())
1095  }
1096}
1097
1098#[cfg(any(feature = "alloc", feature = "std"))]
1099const _: () = {
1100  use bytes::{Buf, BufMut, buf::UninitSlice};
1101
1102  use crate::macros::{forward_buf, forward_buf_mut};
1103
1104  impl Buf for Buffer {
1105    #[cfg_attr(not(coverage), inline(always))]
1106    fn remaining(&self) -> usize {
1107      Self::remaining(self)
1108    }
1109
1110    #[cfg_attr(not(coverage), inline(always))]
1111    fn chunk(&self) -> &[u8] {
1112      self.borrow()
1113    }
1114
1115    #[cfg_attr(not(coverage), inline(always))]
1116    fn advance(&mut self, cnt: usize) {
1117      Self::advance(self, cnt);
1118    }
1119
1120    forward_buf! {
1121      i16,
1122      i32,
1123      i64,
1124      i128,
1125      u16,
1126      u32,
1127      u64,
1128      u128,
1129      f32,
1130      f64,
1131    }
1132  }
1133
1134  #[cfg(any(feature = "alloc", feature = "std"))]
1135  unsafe impl BufMut for Buffer {
1136    #[cfg_attr(not(coverage), inline(always))]
1137    fn remaining_mut(&self) -> usize {
1138      Self::remaining_mut(self)
1139    }
1140
1141    #[cfg_attr(not(coverage), inline(always))]
1142    unsafe fn advance_mut(&mut self, cnt: usize) {
1143      // SAFETY: forwards to the inherent `Buffer::advance_mut` which has
1144      // the same safety contract as the trait method.
1145      unsafe { Self::advance_mut(self, cnt) };
1146    }
1147
1148    #[cfg_attr(not(coverage), inline(always))]
1149    fn chunk_mut(&mut self) -> &mut UninitSlice {
1150      let end = self.end.to_usize();
1151      if end >= INLINE_CAP {
1152        return UninitSlice::new(&mut []);
1153      }
1154      UninitSlice::uninit(&mut self.buf[end..])
1155    }
1156
1157    #[cfg_attr(not(coverage), inline(always))]
1158    fn put_slice(&mut self, src: &[u8]) {
1159      Self::put_slice(self, src);
1160    }
1161
1162    #[cfg_attr(not(coverage), inline(always))]
1163    fn put_bytes(&mut self, val: u8, requested: usize) {
1164      Self::put_bytes(self, val, requested);
1165    }
1166
1167    forward_buf_mut! {
1168      i16,
1169      i32,
1170      i64,
1171      i128,
1172      u16,
1173      u32,
1174      u64,
1175      u128,
1176      f32,
1177      f64,
1178    }
1179  }
1180};
1181
1182/// Panic with a nice error message.
1183#[cold]
1184fn panic_advance(available: usize, requested: usize) -> ! {
1185  panic!("advance out of bounds: the len is {available} but advancing by {requested}",);
1186}
1187
1188#[cold]
1189fn panic_does_not_fit(size: usize, nbytes: usize) -> ! {
1190  panic!(
1191    "size too large: the integer type can fit {} bytes, but nbytes is {}",
1192    size, nbytes
1193  );
1194}
1195
1196const _: () = {
1197  const fn _assert<T: Send + Sync>() {}
1198  _assert::<Buffer>();
1199};