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};