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::*;
12use crate::utf8_edit::{RawUtf8Storage, replace_bytes};
13
14mod cmp;
15mod fmt;
16mod from;
17mod io;
18mod iter;
19mod ops;
20
21#[cfg(any(feature = "alloc", feature = "std"))]
22pub(crate) use io::sign_extend;
23#[cfg(any(feature = "alloc", feature = "std"))]
24pub(crate) use io::{checked_signed_range, checked_unsigned_range};
25
26#[cfg(feature = "arbitrary")]
27mod arbitrary;
28#[cfg(feature = "borsh")]
29mod borsh;
30#[cfg(all(feature = "quickcheck", any(feature = "std", feature = "alloc")))]
31mod quickcheck;
32#[cfg(feature = "serde")]
33mod serde;
34
35#[cfg(feature = "pyo3")]
36mod python;
37
38#[cfg(feature = "wasm")]
39mod wasm;
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)]
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 ///
335 /// Returns `false` without changing the buffer when `additional` cannot
336 /// fit after reclaiming the consumed prefix.
337 ///
338 /// # Examples
339 ///
340 /// ```
341 /// use smol_bytes::{Buffer, INLINE_CAP};
342 ///
343 /// let mut buffer = Buffer::from(*b"abcd");
344 /// buffer.advance(2);
345 /// assert!(!buffer.try_reclaim(usize::MAX));
346 /// assert_eq!(buffer.as_slice(), b"cd");
347 /// assert_eq!(buffer.capacity(), INLINE_CAP - 2);
348 /// assert!(buffer.try_reclaim(60));
349 /// assert_eq!(buffer.as_slice(), b"cd");
350 /// assert_eq!(buffer.capacity(), INLINE_CAP);
351 /// ```
352 #[cfg_attr(not(coverage), inline(always))]
353 pub fn try_reclaim(&mut self, additional: usize) -> bool {
354 if additional <= self.remaining_mut() {
355 return true;
356 }
357
358 let len = self.len();
359 if additional > INLINE_CAP - len {
360 return false;
361 }
362
363 let cur = self.cur.to_usize();
364 if cur != 0 {
365 // `copy_within` is overlap-safe; the invariant keeps `cur..end` within
366 // the initialized prefix and its length is exactly `len`.
367 self.buf.copy_within(cur..self.end.to_usize(), 0);
368 }
369
370 self.cur = InlineSize::_V0;
371 // SAFETY: `len <= INLINE_CAP`, so it is a valid `InlineSize`; the copy
372 // above established that `buf[..len]` is initialized.
373 self.end = unsafe { InlineSize::from_u8(len as u8) };
374 true
375 }
376
377 /// Sets the visible length of the buffer.
378 ///
379 /// This will explicitly set the size of the buffer without actually
380 /// modifying the data, so it is up to the caller to ensure that the data
381 /// has been initialized.
382 ///
383 /// ## Safety
384 ///
385 /// - `len` must not exceed [`capacity`](Self::capacity).
386 /// - Every byte in the current view's `0..len` range must be initialized.
387 ///
388 /// ## Examples
389 ///
390 /// ```
391 /// use smol_bytes::Buffer;
392 ///
393 /// let mut b = Buffer::try_from(&b"hello world"[..]).unwrap();
394 ///
395 /// unsafe {
396 /// b.set_len(5);
397 /// }
398 ///
399 /// assert_eq!(&b[..], b"hello");
400 ///
401 /// unsafe {
402 /// b.set_len(11);
403 /// }
404 ///
405 /// assert_eq!(&b[..], b"hello world");
406 /// ```
407 #[allow(clippy::missing_safety_doc)]
408 #[cfg_attr(not(coverage), inline(always))]
409 pub const unsafe fn set_len(&mut self, len: usize) {
410 debug_assert!(len <= self.capacity(), "set_len out of bounds");
411 let end = self.cur.to_usize() + len;
412 // SAFETY: the caller guarantees `len <= self.capacity()`, so
413 // `cur + len <= INLINE_CAP` and is a valid `InlineSize` discriminant.
414 self.end = unsafe { InlineSize::from_u8(end as u8) };
415 }
416
417 /// Advance the internal cursor of the `Buffer`
418 ///
419 /// The next call to `as_slice()` will return a slice starting `cnt` bytes
420 /// further into the underlying buffer.
421 ///
422 /// ## Examples
423 ///
424 /// ```
425 /// use smol_bytes::{Buffer, INLINE_CAP};
426 ///
427 /// let mut buf = Buffer::try_from(&b"hello world"[..]).unwrap();
428 ///
429 /// assert_eq!(buf.as_slice(), &b"hello world"[..]);
430 ///
431 /// buf.advance(6);
432 ///
433 /// assert_eq!(buf.as_slice(), &b"world"[..]);
434 ///
435 /// // advancing will also reduce capacity
436 /// assert_eq!(buf.capacity(), INLINE_CAP - 6);
437 /// ```
438 ///
439 /// ## Panics
440 ///
441 /// This function panics if `cnt > self.remaining()`.
442 #[cfg_attr(not(coverage), inline(always))]
443 pub fn advance(&mut self, requested: usize) {
444 if let Err(err) = self.try_advance(requested) {
445 panic_advance(err.available, err.requested)
446 }
447 }
448
449 /// Tries to advance the internal cursor of the `Buffer`.
450 ///
451 /// Returns `Err(OutOfBounds)` if `requested` exceeds the remaining length.
452 #[cfg_attr(not(coverage), inline(always))]
453 pub fn try_advance(&mut self, requested: usize) -> Result<(), OutOfBounds> {
454 if requested == 0 {
455 return Ok(());
456 }
457
458 let available = self.remaining();
459 if available < requested {
460 return Err(OutOfBounds::new(requested, available));
461 }
462 // SAFETY: `requested <= remaining == end - cur`, so the new cursor is
463 // at most `end` and therefore at most `INLINE_CAP`.
464 self.cur = unsafe { InlineSize::from_u8(self.cur.to_u8() + requested as u8) };
465 Ok(())
466 }
467
468 /// Advance the internal write cursor of the `Buffer`
469 ///
470 /// The next call to [`spare_capacity_mut`](Self::spare_capacity_mut) will return a slice starting `cnt` bytes
471 /// further into the underlying buffer.
472 ///
473 /// ## Safety
474 ///
475 /// The caller must ensure that the next `cnt` bytes of `chunk` are
476 /// initialized.
477 ///
478 /// ## Examples
479 ///
480 /// ```
481 /// use smol_bytes::Buffer;
482 ///
483 /// let mut buf = Buffer::new();
484 ///
485 /// // Write some data
486 /// unsafe {
487 /// let tmp = buf.spare_capacity_mut();
488 /// core::ptr::copy(b"he".as_ptr(), tmp.as_mut_ptr() as _, 2);
489 /// buf.advance_mut(2);
490 /// }
491 ///
492 /// // write more bytes
493 /// unsafe {
494 /// let tmp = buf.spare_capacity_mut();
495 /// core::ptr::copy(b"llo".as_ptr(), tmp.as_mut_ptr() as _, 3);
496 /// buf.advance_mut(3);
497 /// }
498 ///
499 /// assert_eq!(5, buf.len());
500 /// assert_eq!(buf, "hello".as_bytes());
501 /// ```
502 ///
503 /// ## Panics
504 ///
505 /// This function panic if `requested > self.remaining_mut()`.
506 pub unsafe fn advance_mut(&mut self, requested: usize) {
507 let available = self.remaining_mut();
508 if requested > available {
509 panic_advance(available, requested)
510 }
511
512 // SAFETY: `requested <= remaining_mut == INLINE_CAP - end`, so the new
513 // absolute end is a valid `InlineSize` and the caller initialized the
514 // bytes being exposed, as required by `advance_mut`.
515 self.end = unsafe { InlineSize::from_u8(self.end.to_u8() + requested as u8) };
516 }
517
518 /// Shortens the buffer, keeping the first len bytes and dropping the rest.
519 ///
520 /// If len is greater than the buffer’s current length, this has no effect.
521 ///
522 /// Existing underlying capacity is preserved.
523 ///
524 /// ## Example
525 ///
526 /// ```rust
527 /// use smol_bytes::Buffer;
528 ///
529 /// let mut bytes = Buffer::try_from(&b"hello world"[..]).unwrap();
530 ///
531 /// bytes.truncate(5);
532 /// assert_eq!(bytes.as_mut_slice(), b"hello");
533 /// ```
534 #[cfg_attr(not(coverage), inline(always))]
535 pub const fn truncate(&mut self, new_len: usize) {
536 if new_len >= self.len() {
537 return;
538 }
539
540 let new_end = self.cur.to_usize() + new_len;
541 // SAFETY: `new_len < self.len() == end - cur`, so `new_end < end` and
542 // remains a valid `InlineSize`. No bytes are moved or newly exposed.
543 self.end = unsafe { InlineSize::from_u8(new_end as u8) };
544 }
545
546 /// Splits the buffer into two at the given index.
547 ///
548 /// Afterwards `self` contains elements `[0, at)`, and the returned `Buffer`
549 /// contains elements `[at, len)`.
550 ///
551 /// This operation copies the tail into a new `Buffer`.
552 ///
553 /// ## Example
554 ///
555 /// ```rust
556 /// use smol_bytes::Buffer;
557 ///
558 /// let mut a = Buffer::try_from(&b"hello world"[..]).unwrap();
559 /// let b = a.split_off(5);
560 /// assert_eq!(a.as_slice(), b"hello");
561 /// assert_eq!(b.as_slice(), b" world");
562 /// ```
563 ///
564 /// ## Panics
565 ///
566 /// Panics if `at > len`.
567 #[must_use = "consider Buffer::truncate if you don't need the other half"]
568 pub fn split_off(&mut self, at: usize) -> Self {
569 self
570 .try_split_off(at)
571 .unwrap_or_else(|_| panic!("split_off out of bounds: {} > {}", at, self.remaining()))
572 }
573
574 /// Splits the buffer into two at the given index.
575 ///
576 /// Afterwards `self` contains elements `[at, len)`, and the returned `Buffer`
577 /// contains elements `[0, at)`.
578 ///
579 /// This operation copies the head into a new `Buffer`.
580 ///
581 /// ## Example
582 ///
583 /// ```rust
584 /// use smol_bytes::Buffer;
585 ///
586 /// let mut a = Buffer::try_from(&b"hello world"[..]).unwrap();
587 /// let b = a.split_to(5);
588 /// assert_eq!(b.as_slice(), b"hello");
589 /// assert_eq!(a.as_slice(), b" world");
590 /// ```
591 ///
592 /// ## Panics
593 ///
594 /// Panics if `at > len`.
595 #[must_use = "consider Buffer::advance if you don't need the other half"]
596 pub fn split_to(&mut self, at: usize) -> Self {
597 self
598 .try_split_to(at)
599 .unwrap_or_else(|_| panic!("split_to out of bounds: {} > {}", at, self.remaining()))
600 }
601
602 /// Tries to split the buffer into two at the given index.
603 ///
604 /// Afterwards `self` contains elements `[0, at)`, and the returned `Buffer`
605 /// contains elements `[at, len)`.
606 ///
607 /// Returns `Err(OutOfBounds)` if `at > remaining()`.
608 ///
609 /// ## Example
610 ///
611 /// ```rust
612 /// use smol_bytes::Buffer;
613 ///
614 /// let mut a = Buffer::try_from(&b"hello world"[..]).unwrap();
615 /// let b = a.try_split_off(5).unwrap();
616 /// assert_eq!(a.as_slice(), b"hello");
617 /// assert_eq!(b.as_slice(), b" world");
618 /// ```
619 #[must_use = "consider Buffer::truncate if you don't need the other half"]
620 pub const fn try_split_off(&mut self, at: usize) -> Result<Self, OutOfBounds> {
621 let len = self.remaining();
622 if at > len {
623 return Err(OutOfBounds::new(at, len));
624 }
625
626 let tail_len = len - at;
627 // SAFETY: `at <= len` proves the source range `at..len` is initialized;
628 // `tail_len <= INLINE_CAP` keeps the destination in `new_buf`, and the
629 // distinct buffers cannot overlap.
630 let tail = unsafe {
631 let mut new_buf = Self::new();
632 if tail_len > 0 {
633 let src = self.as_slice().as_ptr().add(at);
634 copy_nonoverlapping(src, new_buf.buf.as_mut_ptr() as *mut u8, tail_len);
635 new_buf.end = InlineSize::from_u8(tail_len as u8);
636 }
637 new_buf
638 };
639
640 self.truncate(at);
641 Ok(tail)
642 }
643
644 /// Tries to split the buffer into two at the given index.
645 ///
646 /// Afterwards `self` contains elements `[at, len)`, and the returned `Buffer`
647 /// contains elements `[0, at)`.
648 ///
649 /// Returns `Err(OutOfBounds)` if `at > remaining()`.
650 ///
651 /// ## Example
652 ///
653 /// ```rust
654 /// use smol_bytes::Buffer;
655 ///
656 /// let mut a = Buffer::try_from(&b"hello world"[..]).unwrap();
657 /// let b = a.try_split_to(5).unwrap();
658 /// assert_eq!(b.as_slice(), b"hello");
659 /// assert_eq!(a.as_slice(), b" world");
660 /// ```
661 #[must_use = "consider Buffer::advance if you don't need the other half"]
662 pub const fn try_split_to(&mut self, at: usize) -> Result<Self, OutOfBounds> {
663 let len = self.remaining();
664 if at > len {
665 return Err(OutOfBounds::new(at, len));
666 }
667
668 // SAFETY: `at <= len <= INLINE_CAP` proves the source prefix is
669 // initialized and the destination fits; the distinct buffers cannot
670 // overlap.
671 let head = unsafe {
672 let mut new_buf = Self::new();
673 if at > 0 {
674 let src = self.as_slice().as_ptr();
675 copy_nonoverlapping(src, new_buf.buf.as_mut_ptr() as *mut u8, at);
676 new_buf.end = InlineSize::from_u8(at as u8);
677 }
678 new_buf
679 };
680
681 // SAFETY: `at <= remaining == end - cur`, so the new cursor is at most
682 // `end` and remains a valid `InlineSize`.
683 self.cur = unsafe { InlineSize::from_u8(self.cur.to_u8() + at as u8) };
684 Ok(head)
685 }
686
687 /// Creates a new buffer containing a copy of the specified range.
688 ///
689 /// ## Example
690 ///
691 /// ```rust
692 /// use smol_bytes::Buffer;
693 ///
694 /// let buf = Buffer::try_from(&b"hello world"[..]).unwrap();
695 /// let slice = buf.slice(0..5);
696 /// assert_eq!(slice.as_slice(), b"hello");
697 /// ```
698 ///
699 /// ## Panics
700 ///
701 /// Panics if the range is out of bounds.
702 pub fn slice(&self, range: impl RangeBounds<usize>) -> Self {
703 self.try_slice(range).unwrap_or_else(|e| panic!("{e}"))
704 }
705
706 /// Tries to create a new buffer containing a copy of the specified range.
707 ///
708 /// Returns `Err(OutOfBounds)` if the range is out of bounds or the slice is too large.
709 ///
710 /// ## Example
711 ///
712 /// ```rust
713 /// use smol_bytes::Buffer;
714 ///
715 /// let buf = Buffer::try_from(&b"hello world"[..]).unwrap();
716 /// let slice = buf.try_slice(0..5).unwrap();
717 /// assert_eq!(slice.as_slice(), b"hello");
718 /// ```
719 pub fn try_slice(&self, range: impl RangeBounds<usize>) -> Result<Self, RangeOutOfBounds> {
720 let len = self.len();
721 let (begin, end) = normalize_range(range, len)?;
722
723 if begin == end {
724 return Ok(Self::new());
725 }
726
727 // SAFETY: `normalize_range` proves `begin <= end <= self.len()`, so the
728 // subslice is initialized and its length is at most `INLINE_CAP`.
729 Ok(unsafe { Self::copy_from_slice(&self.as_slice()[begin..end]) })
730 }
731
732 /// Replaces a range of visible bytes with `replacement`.
733 ///
734 /// # Panics
735 ///
736 /// Panics if the range is invalid or the replacement cannot fit in the
737 /// remaining tail capacity.
738 pub fn replace_range(&mut self, range: impl RangeBounds<usize>, replacement: &[u8]) {
739 self
740 .try_replace_range(range, replacement)
741 .unwrap_or_else(|error| panic!("replace_range failed: {error}"));
742 }
743
744 /// Tries to replace a range of visible bytes with `replacement`.
745 ///
746 /// The range is normalized before capacity is checked. On error this buffer
747 /// is unchanged; consumed prefix storage is not reclaimed implicitly.
748 pub fn try_replace_range(
749 &mut self,
750 range: impl RangeBounds<usize>,
751 replacement: &[u8],
752 ) -> Result<(), ByteEditError> {
753 let old_len = self.len();
754 let (start, end) = normalize_range(range, old_len)?;
755 let removed = end - start;
756 let growth = replacement.len().saturating_sub(removed);
757 let available = self.remaining_mut();
758 if growth > available {
759 return Err(
760 TryPutError {
761 requested: growth,
762 available,
763 }
764 .into(),
765 );
766 }
767
768 let mut storage = RawUtf8Storage::fixed(self);
769 replace_bytes(&mut storage, start, end, replacement);
770 Ok(())
771 }
772
773 /// Appends a copy of the specified visible byte range.
774 ///
775 /// # Panics
776 ///
777 /// Panics if the range is invalid or its bytes do not fit in the remaining
778 /// tail capacity.
779 pub fn extend_from_within(&mut self, range: impl RangeBounds<usize>) {
780 self
781 .try_extend_from_within(range)
782 .unwrap_or_else(|error| panic!("extend_from_within failed: {error}"));
783 }
784
785 /// Tries to append a copy of the specified visible byte range.
786 ///
787 /// The range is normalized before capacity is checked. On error this buffer
788 /// is unchanged; consumed prefix storage is not reclaimed implicitly.
789 pub fn try_extend_from_within(
790 &mut self,
791 range: impl RangeBounds<usize>,
792 ) -> Result<(), ByteEditError> {
793 let old_len = self.len();
794 let (start, end) = normalize_range(range, old_len)?;
795 let count = end - start;
796 let new_len = old_len.checked_add(count).expect("buffer length overflow");
797 let available = self.remaining_mut();
798 if count > available {
799 return Err(
800 TryPutError {
801 requested: count,
802 available,
803 }
804 .into(),
805 );
806 }
807
808 if count == 0 {
809 return Ok(());
810 }
811
812 self.resize(new_len, 0);
813 self.as_mut_slice().copy_within(start..end, old_len);
814 Ok(())
815 }
816
817 /// Resizes the buffer to the specified length, filling with `value` if expanding.
818 ///
819 /// ## Example
820 ///
821 /// ```rust
822 /// use smol_bytes::Buffer;
823 ///
824 /// let mut buf = Buffer::try_from(&b"hello"[..]).unwrap();
825 /// buf.resize(8, b'x');
826 /// assert_eq!(buf.as_slice(), b"helloxxx");
827 ///
828 /// buf.resize(3, 0);
829 /// assert_eq!(buf.as_slice(), b"hel");
830 /// ```
831 ///
832 /// ## Panics
833 ///
834 /// Panics if the new length exceeds capacity.
835 pub fn resize(&mut self, new_len: usize, value: u8) {
836 let current_len = self.remaining();
837
838 if new_len == current_len {
839 return;
840 }
841
842 if new_len < current_len {
843 self.truncate(new_len);
844 return;
845 }
846
847 // Expanding
848 let additional = new_len - current_len;
849 assert!(
850 self.remaining_mut() >= additional,
851 "resize exceeds capacity: {} + {} > {}",
852 current_len,
853 additional,
854 self.capacity()
855 );
856
857 self.put_bytes(value, additional);
858 }
859
860 /// Tries to resize the buffer to the specified length, filling with `value`
861 /// if expanding.
862 ///
863 /// Returns `Err(OutOfBounds)` if the new length exceeds capacity.
864 ///
865 /// ## Example
866 ///
867 /// ```rust
868 /// use smol_bytes::Buffer;
869 ///
870 /// let mut buf = Buffer::try_from(&b"hello"[..]).unwrap();
871 /// assert!(buf.try_resize(8, b'x').is_ok());
872 /// assert_eq!(buf.as_slice(), b"helloxxx");
873 ///
874 /// assert!(buf.try_resize(3, 0).is_ok());
875 /// assert_eq!(buf.as_slice(), b"hel");
876 /// ```
877 pub const fn try_resize(&mut self, new_len: usize, value: u8) -> Result<(), OutOfBounds> {
878 let current_len = self.remaining();
879
880 if new_len == current_len {
881 return Ok(());
882 }
883
884 if new_len < current_len {
885 self.truncate(new_len);
886 return Ok(());
887 }
888
889 // Expanding
890 let additional = new_len - current_len;
891 if self.remaining_mut() < additional {
892 return Err(OutOfBounds::new(new_len, self.capacity()));
893 }
894
895 match self.try_put_bytes(value, additional) {
896 Ok(()) => Ok(()),
897 Err(_) => {
898 // The identical capacity check above makes this branch unreachable;
899 // retain a defensive error instead of relying on unchecked state.
900 Err(OutOfBounds::new(new_len, self.capacity()))
901 }
902 }
903 }
904
905 /// Clears the buffer, removing all data. Existing capacity is preserved.
906 ///
907 /// ## Example
908 ///
909 /// ```rust
910 /// use smol_bytes::Buffer;
911 ///
912 /// let mut bytes = Buffer::try_from(&b"hello world"[..]).unwrap();
913 /// bytes.clear();
914 /// assert_eq!(bytes.len(), 0);
915 /// ```
916 #[cfg_attr(not(coverage), inline(always))]
917 pub const fn clear(&mut self) {
918 self.end = InlineSize::_V0;
919 self.cur = InlineSize::_V0;
920 }
921
922 /// Returns the remaining spare capacity of the buffer as a slice of [`MaybeUninit<u8>`].
923 ///
924 /// 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.
925 ///
926 /// ## Example
927 ///
928 /// ```
929 /// use smol_bytes::{Buffer, INLINE_CAP};
930 ///
931 /// let mut buf = Buffer::new();
932 ///
933 /// // Fill in the first 3 elements.
934 /// let uninit = buf.spare_capacity_mut();
935 /// uninit[0].write(0);
936 /// uninit[1].write(1);
937 /// uninit[2].write(2);
938 ///
939 /// // Mark the first 3 bytes of the buffer as being initialized.
940 /// unsafe {
941 /// buf.set_len(3);
942 /// }
943 ///
944 /// assert_eq!(buf.as_slice(), &[0, 1, 2]);
945 /// ```
946 #[cfg_attr(not(coverage), inline(always))]
947 pub const fn spare_capacity_mut(&mut self) -> &mut [MaybeUninit<u8>] {
948 let end = self.end.to_usize();
949 // SAFETY: the invariant guarantees `end <= INLINE_CAP`; `buf.add(end)`
950 // starts the uninitialized tail and the returned length stays in `buf`.
951 unsafe { from_raw_parts_mut(self.buf.as_mut_ptr().add(end), INLINE_CAP - end) }
952 }
953
954 /// Returns the capacity of the buffer.
955 ///
956 /// The capacity is not always equal to [`INLINE_CAP`], as the [`advance`](Self::advance) method
957 /// may move the underlying cursor forward, reducing the available capacity.
958 #[cfg_attr(not(coverage), inline(always))]
959 pub const fn capacity(&self) -> usize {
960 INLINE_CAP - self.cur.to_usize()
961 }
962
963 /// Returns the initialized portion of the buffer as a slice.
964 ///
965 /// This will include all bytes from the start of the buffer up to the current length.
966 #[cfg_attr(not(coverage), inline(always))]
967 pub const fn as_slice(&self) -> &[u8] {
968 let ptr = self.buf.as_ptr() as *const u8;
969 let remaining = self.remaining();
970 // SAFETY: the invariant guarantees `buf[..end]` is initialized and
971 // `cur + remaining == end <= INLINE_CAP`.
972 unsafe { core::slice::from_raw_parts(ptr.add(self.cur.to_usize()), remaining) }
973 }
974
975 /// Returns the mutable initialized portion of the buffer as a mutable slice.
976 ///
977 /// This will include all bytes from the start of the buffer up to the current length.
978 #[cfg_attr(not(coverage), inline(always))]
979 pub const fn as_mut_slice(&mut self) -> &mut [u8] {
980 let ptr = self.buf.as_mut_ptr() as *mut u8;
981 let remaining = Self::remaining(self);
982 // SAFETY: the invariant guarantees `buf[..end]` is initialized and this
983 // exclusive borrow covers exactly `cur..end` within the backing array.
984 unsafe { core::slice::from_raw_parts_mut(ptr.add(self.cur.to_usize()), remaining) }
985 }
986
987 /// Transfer bytes into `self` from `src` and advance the cursor by the
988 /// number of bytes written.
989 ///
990 /// `self` must have enough remaining capacity to contain all of `src`.
991 ///
992 /// ```
993 /// use smol_bytes::{Buffer, INLINE_CAP};
994 ///
995 /// let mut dst = Buffer::new();
996 ///
997 /// {
998 /// dst.put_slice(b"hello");
999 /// assert_eq!(INLINE_CAP - 5, dst.remaining_mut());
1000 /// }
1001 ///
1002 /// assert_eq!(dst, "hello");
1003 /// ```
1004 #[inline]
1005 pub fn put_slice(&mut self, src: &[u8]) {
1006 self
1007 .try_put_slice(src)
1008 .unwrap_or_else(|e| panic_advance(e.available, e.requested))
1009 }
1010
1011 /// Try to transfer bytes into `self` from `src` and advance the cursor by the
1012 /// number of bytes written.
1013 ///
1014 /// `self` must have enough remaining capacity to contain all of `src`.
1015 ///
1016 /// ```
1017 /// use smol_bytes::{Buffer, INLINE_CAP};
1018 ///
1019 /// let mut dst = Buffer::new();
1020 ///
1021 /// {
1022 /// dst.try_put_slice(b"hello").unwrap();
1023 /// assert_eq!(INLINE_CAP - 5, dst.remaining_mut());
1024 /// }
1025 ///
1026 /// assert_eq!("hello", &dst);
1027 /// ```
1028 #[inline]
1029 pub const fn try_put_slice(&mut self, src: &[u8]) -> Result<(), TryPutError> {
1030 let available = self.remaining_mut();
1031 let requested = src.len();
1032
1033 if requested > available {
1034 return Err(TryPutError {
1035 requested,
1036 available,
1037 });
1038 }
1039
1040 let slen = self.end.to_usize();
1041 // SAFETY: `requested <= remaining_mut` proves `slen + requested <=
1042 // INLINE_CAP`; `src` is initialized and cannot overlap this exclusive
1043 // buffer borrow.
1044 unsafe {
1045 copy_nonoverlapping(
1046 src.as_ptr(),
1047 self.buf.as_mut_ptr().add(slen) as _,
1048 requested,
1049 );
1050 }
1051 // SAFETY: the capacity check above proves the new absolute end is at most
1052 // `INLINE_CAP`, and the copy initialized every newly exposed byte.
1053 self.end = unsafe { InlineSize::from_u8(slen as u8 + requested as u8) };
1054 Ok(())
1055 }
1056
1057 /// 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.put_bytes(b'a', 4);
1070 /// assert_eq!(INLINE_CAP - 4, dst.remaining_mut());
1071 /// }
1072 ///
1073 /// assert_eq!("aaaa", &dst);
1074 /// ```
1075 ///
1076 /// ## Panics
1077 ///
1078 /// This function panics if there is not enough remaining capacity in
1079 /// `self`.
1080 #[inline]
1081 pub fn put_bytes(&mut self, val: u8, cnt: usize) {
1082 self
1083 .try_put_bytes(val, cnt)
1084 .unwrap_or_else(|e| panic_advance(e.available, e.requested))
1085 }
1086
1087 /// Try to put `cnt` bytes `val` into `self`.
1088 ///
1089 /// Logically equivalent to calling `self.put_u8(val)` `cnt` times, but may work faster.
1090 ///
1091 /// `self` must have at least `cnt` remaining capacity.
1092 ///
1093 /// ```
1094 /// use smol_bytes::{Buffer, INLINE_CAP};
1095 ///
1096 /// let mut dst = Buffer::new();
1097 ///
1098 /// {
1099 /// dst.try_put_bytes(b'a', 4).unwrap();
1100 /// assert_eq!(INLINE_CAP - 4, dst.remaining_mut());
1101 /// }
1102 ///
1103 /// assert_eq!("aaaa".as_bytes(), &dst);
1104 /// ```
1105 #[inline]
1106 pub const fn try_put_bytes(&mut self, val: u8, cnt: usize) -> Result<(), TryPutError> {
1107 if cnt == 0 {
1108 return Ok(());
1109 }
1110
1111 let available = self.remaining_mut();
1112 if available < cnt {
1113 return Err(TryPutError {
1114 requested: cnt,
1115 available,
1116 });
1117 }
1118
1119 // SAFETY: `cnt <= remaining_mut` proves `end + cnt <= INLINE_CAP`; the
1120 // write initializes exactly the bytes that the new end exposes.
1121 unsafe {
1122 write_bytes(self.buf.as_mut_ptr().add(self.end.to_usize()), val, cnt);
1123 }
1124 // SAFETY: the capacity check above proves the new absolute end is a valid
1125 // `InlineSize`, and `write_bytes` initialized the extended region.
1126 self.end = unsafe { InlineSize::from_u8(self.end.to_u8() + cnt as u8) };
1127 Ok(())
1128 }
1129
1130 /// Put `cnt` bytes `val` into `self`.
1131 ///
1132 /// Logically equivalent to calling `self.put_u8(val)` `cnt` times, but may work faster.
1133 ///
1134 /// `self` must have at least `cnt` remaining capacity.
1135 ///
1136 /// ```
1137 /// use smol_bytes::{Buffer, INLINE_CAP};
1138 ///
1139 /// let mut dst = Buffer::new();
1140 ///
1141 /// {
1142 /// dst.put_u8(b'a');
1143 /// assert_eq!(INLINE_CAP - 1, dst.remaining_mut());
1144 /// }
1145 ///
1146 /// assert_eq!("a", &dst);
1147 /// ```
1148 ///
1149 /// ## Panics
1150 ///
1151 /// This function panics if there is not enough remaining capacity in
1152 /// `self`.
1153 #[inline]
1154 pub fn put_u8(&mut self, val: u8) {
1155 self
1156 .try_put_u8(val)
1157 .unwrap_or_else(|e| panic_advance(e.available, e.requested))
1158 }
1159
1160 /// Try to put `cnt` bytes `val` into `self`.
1161 ///
1162 /// Logically equivalent to calling `self.put_u8(val)` `cnt` times, but may work faster.
1163 ///
1164 /// `self` must have at least `cnt` remaining capacity.
1165 ///
1166 /// ```
1167 /// use smol_bytes::{Buffer, INLINE_CAP};
1168 ///
1169 /// let mut dst = Buffer::new();
1170 ///
1171 /// {
1172 /// dst.try_put_u8(b'a').unwrap();
1173 /// assert_eq!(INLINE_CAP - 1, dst.remaining_mut());
1174 /// }
1175 ///
1176 /// assert_eq!("a".as_bytes(), &dst);
1177 /// ```
1178 ///
1179 /// ## Panics
1180 ///
1181 /// This function panics if there is not enough remaining capacity in
1182 /// `self`.
1183 #[inline]
1184 pub const fn try_put_u8(&mut self, val: u8) -> Result<(), TryPutError> {
1185 let available = self.remaining_mut();
1186 if available < 1 {
1187 return Err(TryPutError {
1188 requested: 1,
1189 available,
1190 });
1191 }
1192
1193 self.buf[self.end.to_usize()].write(val);
1194 // SAFETY: `remaining_mut >= 1` proves `end + 1 <= INLINE_CAP`, and the
1195 // preceding write initialized the byte being exposed.
1196 self.end = unsafe { InlineSize::from_u8(self.end.to_u8() + 1) };
1197 Ok(())
1198 }
1199}
1200
1201#[cfg(any(feature = "alloc", feature = "std"))]
1202const _: () = {
1203 use bytes::{Buf, BufMut, buf::UninitSlice};
1204
1205 use crate::macros::forward_buf_mut;
1206
1207 impl Buf for Buffer {
1208 #[cfg_attr(not(coverage), inline(always))]
1209 fn remaining(&self) -> usize {
1210 Self::remaining(self)
1211 }
1212
1213 #[cfg_attr(not(coverage), inline(always))]
1214 fn chunk(&self) -> &[u8] {
1215 self.borrow()
1216 }
1217
1218 #[cfg_attr(not(coverage), inline(always))]
1219 fn advance(&mut self, cnt: usize) {
1220 Self::advance(self, cnt);
1221 }
1222
1223 fn get_int(&mut self, nbytes: usize) -> i64 {
1224 sign_extend(::bytes::Buf::get_uint(self, nbytes), nbytes)
1225 }
1226
1227 fn get_int_le(&mut self, nbytes: usize) -> i64 {
1228 sign_extend(::bytes::Buf::get_uint_le(self, nbytes), nbytes)
1229 }
1230
1231 fn get_int_ne(&mut self, nbytes: usize) -> i64 {
1232 sign_extend(::bytes::Buf::get_uint_ne(self, nbytes), nbytes)
1233 }
1234
1235 fn try_get_int(&mut self, nbytes: usize) -> Result<i64, bytes::TryGetError> {
1236 ::bytes::Buf::try_get_uint(self, nbytes).map(|value| sign_extend(value, nbytes))
1237 }
1238
1239 fn try_get_int_le(&mut self, nbytes: usize) -> Result<i64, bytes::TryGetError> {
1240 ::bytes::Buf::try_get_uint_le(self, nbytes).map(|value| sign_extend(value, nbytes))
1241 }
1242
1243 fn try_get_int_ne(&mut self, nbytes: usize) -> Result<i64, bytes::TryGetError> {
1244 ::bytes::Buf::try_get_uint_ne(self, nbytes).map(|value| sign_extend(value, nbytes))
1245 }
1246 }
1247
1248 #[cfg(any(feature = "alloc", feature = "std"))]
1249 unsafe impl BufMut for Buffer {
1250 #[cfg_attr(not(coverage), inline(always))]
1251 fn remaining_mut(&self) -> usize {
1252 Self::remaining_mut(self)
1253 }
1254
1255 #[cfg_attr(not(coverage), inline(always))]
1256 unsafe fn advance_mut(&mut self, cnt: usize) {
1257 // SAFETY: forwards to the inherent `Buffer::advance_mut` which has
1258 // the same safety contract as the trait method.
1259 unsafe { Self::advance_mut(self, cnt) };
1260 }
1261
1262 #[cfg_attr(not(coverage), inline(always))]
1263 fn chunk_mut(&mut self) -> &mut UninitSlice {
1264 let end = self.end.to_usize();
1265 if end >= INLINE_CAP {
1266 return UninitSlice::new(&mut []);
1267 }
1268 UninitSlice::uninit(&mut self.buf[end..])
1269 }
1270
1271 #[cfg_attr(not(coverage), inline(always))]
1272 fn put_slice(&mut self, src: &[u8]) {
1273 Self::put_slice(self, src);
1274 }
1275
1276 #[cfg_attr(not(coverage), inline(always))]
1277 fn put_bytes(&mut self, val: u8, requested: usize) {
1278 Self::put_bytes(self, val, requested);
1279 }
1280
1281 forward_buf_mut! {
1282 i16,
1283 i32,
1284 i64,
1285 i128,
1286 u16,
1287 u32,
1288 u64,
1289 u128,
1290 f32,
1291 f64,
1292 }
1293 }
1294};
1295
1296/// Panic with a nice error message.
1297#[cold]
1298fn panic_advance(available: usize, requested: usize) -> ! {
1299 panic!("advance out of bounds: the len is {available} but advancing by {requested}",);
1300}
1301
1302#[cold]
1303fn panic_does_not_fit(size: usize, nbytes: usize) -> ! {
1304 panic!(
1305 "size too large: the integer type can fit {} bytes, but nbytes is {}",
1306 size, nbytes
1307 );
1308}
1309
1310const _: () = {
1311 const fn _assert<T: Send + Sync>() {}
1312 _assert::<Buffer>();
1313};