Skip to main content

bump_scope/
fixed_bump_string.rs

1use core::{
2    borrow::{Borrow, BorrowMut},
3    fmt::{self, Debug, Display},
4    hash::Hash,
5    mem::{self, MaybeUninit},
6    ops::{self, Deref, DerefMut, Range, RangeBounds},
7    ptr::{self, NonNull},
8    str,
9};
10
11use crate::{
12    BumpBox, BumpString, ErrorBehavior, FixedBumpVec, FromUtf8Error, NoDrop,
13    alloc::AllocError,
14    owned_str,
15    polyfill::{self, non_null, transmute_mut},
16    traits::BumpAllocatorTypedScope,
17};
18
19#[cfg(feature = "panic-on-alloc")]
20use crate::panic_on_error;
21
22mod raw;
23
24pub(crate) use raw::RawFixedBumpString;
25
26/// A type like [`BumpString`] but with a fixed capacity.
27///
28/// It can be constructed using [`with_capacity_in`] or from a `BumpBox` via [`from_init`] or [`from_uninit`].
29///
30/// ## Using it like `BumpString`
31///
32/// This type is also useful when you want a growing `BumpString` but don't want to carry around a reference to
33/// the `Bump(Scope)`. You can use it this way by first converting it to a `BumpString` using [`BumpString::from_parts`],
34/// making your changes and then turning it back into a `FixedBumpString` with [`BumpString::into_fixed_string`].
35///
36/// Not storing the `Bump(Scope)` allows you to call bump allocator methods that require `&mut`,
37/// like [`scoped`](crate::Bump::scoped).
38///
39/// # Examples
40/// ```
41/// # use bump_scope::{Bump, FixedBumpString};
42/// # let bump: Bump = Bump::new();
43/// let mut string = FixedBumpString::with_capacity_in(9, &bump);
44///
45/// string.push_str("foo");
46/// string.push_str("bar");
47/// string.push_str("baz");
48///
49/// let str = string.into_str();
50///
51/// assert_eq!(str, "foobarbaz");
52/// ```
53///
54/// Growing it via `BumpString`:
55///
56/// ```
57/// # use bump_scope::{Bump, BumpScope, BumpString, FixedBumpString};
58/// struct MyBuilder<'a, 'b> {
59///     bump: &'b mut BumpScope<'a>,
60///     string: FixedBumpString<'a>,
61/// }
62///
63/// impl<'a, 'b> MyBuilder<'a, 'b> {
64///     fn push_str(&mut self, value: &str) {
65///         let fixed_string = core::mem::take(&mut self.string);
66///         let mut string = BumpString::from_parts(fixed_string, &mut *self.bump);
67///         string.push_str(value);
68///         self.string = string.into_fixed_string();
69///     }
70/// }
71///
72/// let mut bump: Bump = Bump::new();
73///
74/// let mut builder = MyBuilder {
75///     bump: bump.as_mut_scope(),
76///     string: FixedBumpString::new(),
77/// };
78///
79/// builder.push_str("hello");
80/// assert_eq!(builder.string, "hello");
81/// ```
82///
83/// [`with_capacity_in`]: Self::with_capacity_in
84/// [`from_uninit`]: Self::from_uninit
85/// [`from_init`]: Self::from_init
86// `FixedBumpString` and `FixedBumpVec<u8>` have the same repr.
87#[repr(C)]
88pub struct FixedBumpString<'a> {
89    initialized: BumpBox<'a, str>,
90    capacity: usize,
91}
92
93unsafe impl Send for FixedBumpString<'_> {}
94unsafe impl Sync for FixedBumpString<'_> {}
95
96impl<'a> FixedBumpString<'a> {
97    /// Constructs a new empty `FixedBumpString`.
98    ///
99    /// This will not allocate.
100    ///
101    /// # Examples
102    /// ```
103    /// # use bump_scope::FixedBumpString;
104    /// let string = FixedBumpString::new();
105    /// assert_eq!(string.len(), 0);
106    /// assert_eq!(string.capacity(), 0);
107    /// ```
108    #[inline]
109    #[must_use]
110    pub const fn new() -> Self {
111        Self {
112            initialized: BumpBox::EMPTY_STR,
113            capacity: 0,
114        }
115    }
116
117    /// Constructs a new empty `FixedBumpString` with the specified capacity
118    /// in the provided bump allocator.
119    ///
120    /// The string will be able to hold `capacity` bytes.
121    /// If `capacity` is 0, the string will not allocate.
122    ///
123    /// # Panics
124    /// Panics if the allocation fails.
125    ///
126    /// # Examples
127    /// ```
128    /// # use bump_scope::{Bump, FixedBumpString};
129    /// # let bump: Bump = Bump::new();
130    /// let mut s = FixedBumpString::with_capacity_in(10, &bump);
131    ///
132    /// // The String contains no chars, even though it has capacity for more
133    /// assert_eq!(s.len(), 0);
134    ///
135    /// // The string has capacity for 10 bytes...
136    /// for _ in 0..10 {
137    ///     s.push('a');
138    /// }
139    ///
140    /// // ...but another byte will not fit
141    /// assert!(s.try_push('a').is_err());
142    /// ```
143    #[must_use]
144    #[inline(always)]
145    #[cfg(feature = "panic-on-alloc")]
146    pub fn with_capacity_in(capacity: usize, allocator: impl BumpAllocatorTypedScope<'a>) -> Self {
147        panic_on_error(Self::generic_with_capacity_in(capacity, allocator))
148    }
149
150    /// Constructs a new empty `FixedBumpString` with the specified capacity
151    /// in the provided bump allocator.
152    ///
153    /// The string will be able to hold `capacity` bytes.
154    /// If `capacity` is 0, the string will not allocate.
155    ///
156    /// # Errors
157    /// Errors if the allocation fails.
158    ///
159    /// # Examples
160    /// ```
161    /// # use bump_scope::{Bump, FixedBumpString};
162    /// # let bump: Bump = Bump::new();
163    /// let mut s = FixedBumpString::try_with_capacity_in(10, &bump)?;
164    ///
165    /// // The String contains no chars, even though it has capacity for more
166    /// assert_eq!(s.len(), 0);
167    ///
168    /// // The string has capacity for 10 bytes...
169    /// for _ in 0..10 {
170    ///     s.push('a');
171    /// }
172    ///
173    /// // ...but another byte will not fit
174    /// assert!(s.try_push('a').is_err());
175    /// # Ok::<(), bump_scope::alloc::AllocError>(())
176    /// ```
177    #[inline(always)]
178    pub fn try_with_capacity_in(capacity: usize, allocator: impl BumpAllocatorTypedScope<'a>) -> Result<Self, AllocError> {
179        Self::generic_with_capacity_in(capacity, allocator)
180    }
181
182    #[inline]
183    pub(crate) fn generic_with_capacity_in<E: ErrorBehavior>(
184        capacity: usize,
185        allocator: impl BumpAllocatorTypedScope<'a>,
186    ) -> Result<Self, E> {
187        Ok(BumpString::generic_with_capacity_in(capacity, allocator)?.into_fixed_string())
188    }
189
190    /// Turns a `BumpBox<str>` into a full `FixedBumpString`.
191    #[must_use]
192    pub fn from_init(initialized: BumpBox<'a, str>) -> Self {
193        let capacity = initialized.len();
194        Self { initialized, capacity }
195    }
196
197    /// Turns a `BumpBox<[MaybeUninit<u8>]>` into a `FixedBumpString` with a length of `0`.
198    #[must_use]
199    pub fn from_uninit(uninitialized: BumpBox<'a, [MaybeUninit<u8>]>) -> Self {
200        let uninitialized = uninitialized.into_raw();
201        let capacity = uninitialized.len();
202
203        let ptr = non_null::as_non_null_ptr(uninitialized).cast::<u8>();
204        let initialized = unsafe { BumpBox::from_raw(non_null::str_from_utf8(NonNull::slice_from_raw_parts(ptr, 0))) };
205
206        Self { initialized, capacity }
207    }
208
209    /// Converts a vector of bytes to a `FixedBumpString`.
210    ///
211    /// A string ([`FixedBumpString`]) is made of bytes ([`u8`]), and a vector of bytes
212    /// ([`FixedBumpVec<u8>`]) is made of bytes, so this function converts between the
213    /// two. Not all byte slices are valid `FixedBumpString`s, however: `FixedBumpString`
214    /// requires that it is valid UTF-8. `from_utf8()` checks to ensure that
215    /// the bytes are valid UTF-8, and then does the conversion.
216    ///
217    /// If you are sure that the byte slice is valid UTF-8, and you don't want
218    /// to incur the overhead of the validity check, there is an unsafe version
219    /// of this function, [`from_utf8_unchecked`], which has the same behavior
220    /// but skips the check.
221    ///
222    /// This method will take care to not copy the vector, for efficiency's
223    /// sake.
224    ///
225    /// If you need a [`&str`] instead of a `FixedBumpString`, consider
226    /// [`str::from_utf8`].
227    ///
228    /// The inverse of this method is [`into_bytes`].
229    ///
230    /// # Errors
231    ///
232    /// Returns [`Err`] if the slice is not UTF-8 with a description as to why the
233    /// provided bytes are not UTF-8. The vector you moved in is also included.
234    ///
235    /// # Examples
236    ///
237    /// Basic usage:
238    /// ```
239    /// # use bump_scope::{Bump, FixedBumpVec, FixedBumpString};
240    /// # let bump: Bump = Bump::new();
241    /// // some bytes, in a vector
242    /// let mut sparkle_heart = FixedBumpVec::with_capacity_in(4, &bump);
243    /// sparkle_heart.extend_from_slice_copy(&[240, 159, 146, 150]);
244    ///
245    /// // We know these bytes are valid, so we'll use `unwrap()`.
246    /// let sparkle_heart = FixedBumpString::from_utf8(sparkle_heart).unwrap();
247    ///
248    /// assert_eq!("💖", sparkle_heart);
249    /// ```
250    ///
251    /// Incorrect bytes:
252    /// ```
253    /// # use bump_scope::{Bump, FixedBumpVec, FixedBumpString};
254    /// # let bump: Bump = Bump::new();
255    /// // some invalid bytes, in a vector
256    /// let mut sparkle_heart = FixedBumpVec::with_capacity_in(4, &bump);
257    /// sparkle_heart.extend_from_slice_copy(&[0, 159, 146, 150]);
258    ///
259    /// assert!(FixedBumpString::from_utf8(sparkle_heart).is_err());
260    /// ```
261    ///
262    /// [`from_utf8_unchecked`]: Self::from_utf8_unchecked
263    /// [`FixedBumpVec<u8>`]: FixedBumpVec
264    /// [`&str`]: prim@str "&str"
265    /// [`into_bytes`]: Self::into_bytes
266    pub fn from_utf8(vec: FixedBumpVec<'a, u8>) -> Result<Self, FromUtf8Error<FixedBumpVec<'a, u8>>> {
267        match core::str::from_utf8(vec.as_slice()) {
268            // SAFETY: `FixedBumpVec<u8>` and `FixedBumpString` have the same representation;
269            // only the invariant that the bytes are utf8 is different.
270            Ok(_) => Ok(unsafe { mem::transmute(vec) }),
271            Err(error) => Err(FromUtf8Error::new(error, vec)),
272        }
273    }
274
275    /// Converts a vector of bytes to a `FixedBumpString` without checking that the
276    /// string contains valid UTF-8.
277    ///
278    /// See the safe version, [`from_utf8`](Self::from_utf8), for more details.
279    ///
280    /// # Safety
281    ///
282    /// The bytes passed in must be valid UTF-8.
283    ///
284    /// # Examples
285    ///
286    /// ```
287    /// # use bump_scope::{Bump, FixedBumpVec, FixedBumpString};
288    /// # let bump: Bump = Bump::new();
289    ///
290    /// // some bytes, in a vector
291    /// let mut sparkle_heart = FixedBumpVec::with_capacity_in(4, &bump);
292    /// sparkle_heart.extend_from_slice_copy(&[240, 159, 146, 150]);
293    ///
294    /// let sparkle_heart = unsafe {
295    ///     FixedBumpString::from_utf8_unchecked(sparkle_heart)
296    /// };
297    ///
298    /// assert_eq!("💖", sparkle_heart);
299    /// ```
300    #[must_use]
301    pub unsafe fn from_utf8_unchecked(vec: FixedBumpVec<'a, u8>) -> Self {
302        debug_assert!(str::from_utf8(vec.as_slice()).is_ok());
303
304        // SAFETY: `FixedBumpVec<u8>` and `FixedBumpString` have the same representation;
305        // only the invariant that the bytes are utf8 is different.
306        unsafe { mem::transmute(vec) }
307    }
308
309    /// Returns this string's capacity, in bytes.
310    #[must_use]
311    #[inline(always)]
312    pub const fn capacity(&self) -> usize {
313        self.capacity
314    }
315
316    /// Returns the length of this string, in bytes, not [`char`]s or
317    /// graphemes. In other words, it might not be what a human considers the
318    /// length of the string.
319    #[must_use]
320    #[inline(always)]
321    pub const fn len(&self) -> usize {
322        self.initialized.len()
323    }
324
325    /// Returns `true` if this string has a length of zero, and `false` otherwise.
326    #[must_use]
327    #[inline(always)]
328    pub const fn is_empty(&self) -> bool {
329        self.initialized.is_empty()
330    }
331
332    /// Converts this `FixedBumpString` into `&str` that is live for this bump scope.
333    #[must_use]
334    #[inline(always)]
335    pub fn into_str(self) -> &'a mut str {
336        self.initialized.into_mut()
337    }
338
339    /// Converts a `FixedBumpString` into a `BumpBox<str>`.
340    #[must_use]
341    #[inline(always)]
342    pub fn into_boxed_str(self) -> BumpBox<'a, str> {
343        self.initialized
344    }
345
346    /// Turns this `FixedBumpString` into a `BumpString`.
347    #[must_use]
348    #[inline(always)]
349    pub fn into_string<A: BumpAllocatorTypedScope<'a>>(self, allocator: A) -> BumpString<A> {
350        BumpString::from_parts(self, allocator)
351    }
352
353    /// Converts a `FixedBumpString` into a `FixedBumpVec<u8>`.
354    ///
355    /// This consumes the `FixedBumpString`, so we do not need to copy its contents.
356    ///
357    /// # Examples
358    ///
359    /// ```
360    /// # use bump_scope::{Bump, FixedBumpString};
361    /// # let bump: Bump = Bump::new();
362    /// let mut s = FixedBumpString::with_capacity_in(5, &bump);
363    /// s.push_str("hello");
364    /// let bytes = s.into_bytes();
365    ///
366    /// assert_eq!(&[104, 101, 108, 108, 111][..], &bytes[..]);
367    /// ```
368    #[inline(always)]
369    #[must_use = "`self` will be dropped if the result is not used"]
370    pub fn into_bytes(self) -> FixedBumpVec<'a, u8> {
371        // SAFETY: `FixedBumpVec<u8>` and `FixedBumpString` have the same representation;
372        // only the invariant that the bytes are utf8 is different.
373        unsafe { mem::transmute(self) }
374    }
375
376    #[track_caller]
377    #[inline(always)]
378    pub(crate) fn assert_char_boundary(&self, index: usize) {
379        self.initialized.assert_char_boundary(index);
380    }
381
382    /// Splits the string into two by removing the specified range.
383    ///
384    /// This method does not allocate and does not change the order of the elements.
385    ///
386    /// The excess capacity may end up in either string.
387    /// This behavior is different from <code>String::[split_off](alloc_crate::string::String::split_off)</code> which allocates a new string for the split-off bytes
388    /// so the original string keeps its capacity.
389    /// If you rather want that behavior then you can write this instead:
390    /// ```
391    /// # use bump_scope::{Bump, FixedBumpString};
392    /// # let bump: Bump = Bump::new();
393    /// # let mut string = FixedBumpString::with_capacity_in(5, &bump);
394    /// # string.push_str("abcde");
395    /// # let start = 1;
396    /// # let end = 4;
397    /// let mut other = FixedBumpString::with_capacity_in(end - start, &bump);
398    /// other.push_str(&string[start..end]);
399    /// string.drain(start..end);
400    /// # assert_eq!(string, "ae");
401    /// # assert_eq!(other, "bcd");
402    /// ```
403    ///
404    /// # Panics
405    ///
406    /// Panics if the starting point or end point do not lie on a [`char`] boundary, or if they're out of bounds.
407    ///
408    /// # Complexity
409    ///
410    /// This operation takes `O(1)` time if either the range starts at 0, ends at `len`, or is empty.
411    /// Otherwise it takes `O(min(end, len - start))` time.
412    ///
413    /// # Examples
414    ///
415    /// ```
416    /// # use bump_scope::{Bump, FixedBumpString};
417    /// # let bump: Bump = Bump::new();
418    /// let mut string = FixedBumpString::with_capacity_in(20, &bump);
419    /// string.push_str("foobarbazqux");
420    ///
421    /// let foo = string.split_off(..3);
422    /// assert_eq!(foo, "foo");
423    /// assert_eq!(string, "barbazqux");
424    ///
425    /// let qux = string.split_off(6..);
426    /// assert_eq!(qux, "qux");
427    /// assert_eq!(string, "barbaz");
428    ///
429    /// let rb = string.split_off(2..4);
430    /// assert_eq!(rb, "rb");
431    /// assert_eq!(string, "baaz");
432    ///
433    /// let rest = string.split_off(..);
434    /// assert_eq!(rest, "baaz");
435    /// assert_eq!(string, "");
436    /// ```
437    #[inline]
438    #[expect(clippy::return_self_not_must_use)]
439    pub fn split_off(&mut self, range: impl RangeBounds<usize>) -> Self {
440        let len = self.len();
441        let ops::Range { start, end } = polyfill::slice::range(range, ..len);
442        let ptr = non_null::as_non_null_ptr(non_null::str_bytes(self.initialized.ptr()));
443
444        unsafe {
445            if end == len {
446                self.assert_char_boundary(start);
447
448                let lhs = ptr;
449                let rhs = ptr.add(start);
450
451                let lhs_len = start;
452                let rhs_len = len - start;
453
454                let lhs_cap = start;
455                let rhs_cap = self.capacity - lhs_cap;
456
457                self.set_ptr(lhs);
458                self.set_len(lhs_len);
459                self.set_cap(lhs_cap);
460
461                return FixedBumpString {
462                    initialized: BumpBox::from_raw(non_null::str_from_utf8(NonNull::slice_from_raw_parts(rhs, rhs_len))),
463                    capacity: rhs_cap,
464                };
465            }
466
467            if start == 0 {
468                self.assert_char_boundary(end);
469
470                let lhs = ptr;
471                let rhs = ptr.add(end);
472
473                let lhs_len = end;
474                let rhs_len = len - end;
475
476                let lhs_cap = end;
477                let rhs_cap = self.capacity - lhs_cap;
478
479                self.set_ptr(rhs);
480                self.set_len(rhs_len);
481                self.set_cap(rhs_cap);
482
483                return FixedBumpString {
484                    initialized: BumpBox::from_raw(non_null::str_from_utf8(NonNull::slice_from_raw_parts(lhs, lhs_len))),
485                    capacity: lhs_cap,
486                };
487            }
488
489            if start == end {
490                return FixedBumpString::new();
491            }
492
493            self.assert_char_boundary(start);
494            self.assert_char_boundary(end);
495
496            let head_len = start;
497            let tail_len = len - end;
498
499            let range_len = end - start;
500            let remaining_len = len - range_len;
501
502            if head_len < tail_len {
503                // move the range of elements to split off to the start
504                self.as_mut_vec().get_unchecked_mut(..end).rotate_right(range_len);
505
506                let lhs = ptr;
507                let rhs = ptr.add(range_len);
508
509                let lhs_len = range_len;
510                let rhs_len = remaining_len;
511
512                let lhs_cap = range_len;
513                let rhs_cap = self.capacity - lhs_cap;
514
515                self.set_ptr(rhs);
516                self.set_len(rhs_len);
517                self.set_cap(rhs_cap);
518
519                FixedBumpString {
520                    initialized: BumpBox::from_raw(non_null::str_from_utf8(NonNull::slice_from_raw_parts(lhs, lhs_len))),
521                    capacity: lhs_cap,
522                }
523            } else {
524                // move the range of elements to split off to the end
525                self.as_mut_vec().get_unchecked_mut(start..).rotate_left(range_len);
526
527                let lhs = ptr;
528                let rhs = ptr.add(remaining_len);
529
530                let lhs_len = remaining_len;
531                let rhs_len = range_len;
532
533                let lhs_cap = remaining_len;
534                let rhs_cap = self.capacity - lhs_cap;
535
536                self.set_ptr(lhs);
537                self.set_len(lhs_len);
538                self.set_cap(lhs_cap);
539
540                FixedBumpString {
541                    initialized: BumpBox::from_raw(non_null::str_from_utf8(NonNull::slice_from_raw_parts(rhs, rhs_len))),
542                    capacity: rhs_cap,
543                }
544            }
545        }
546    }
547
548    /// Removes the last character from the string buffer and returns it.
549    ///
550    /// Returns [`None`] if this string is empty.
551    ///
552    /// # Examples
553    ///
554    /// ```
555    /// # use bump_scope::{Bump, FixedBumpString};
556    /// # let bump: Bump = Bump::new();
557    /// let mut s = FixedBumpString::with_capacity_in(4, &bump);
558    /// s.push_str("abč");
559    ///
560    /// assert_eq!(s.pop(), Some('č'));
561    /// assert_eq!(s.pop(), Some('b'));
562    /// assert_eq!(s.pop(), Some('a'));
563    ///
564    /// assert_eq!(s.pop(), None);
565    /// ```
566    #[inline]
567    pub fn pop(&mut self) -> Option<char> {
568        self.initialized.pop()
569    }
570
571    /// Truncates this string, removing all contents.
572    ///
573    /// While this means the string will have a length of zero, it does not
574    /// touch its capacity.
575    ///
576    /// # Examples
577    ///
578    /// ```
579    /// # use bump_scope::{Bump, FixedBumpString};
580    /// # let bump: Bump = Bump::new();
581    /// #
582    /// let mut s = FixedBumpString::with_capacity_in(3, &bump);
583    /// s.push_str("foo");
584    ///
585    /// s.clear();
586    ///
587    /// assert!(s.is_empty());
588    /// assert_eq!(s.len(), 0);
589    /// assert!(s.capacity() == 3);
590    /// ```
591    #[inline]
592    pub fn clear(&mut self) {
593        self.initialized.clear();
594    }
595
596    /// Shortens this string to the specified length.
597    ///
598    /// If `new_len` is greater than or equal to the string's current length, this has no
599    /// effect.
600    ///
601    /// Note that this method has no effect on the allocated capacity
602    /// of the string
603    ///
604    /// # Panics
605    ///
606    /// Panics if `new_len` does not lie on a [`char`] boundary.
607    ///
608    /// # Examples
609    ///
610    /// ```
611    /// # use bump_scope::{Bump, FixedBumpString};
612    /// # let bump: Bump = Bump::new();
613    /// let mut s = FixedBumpString::with_capacity_in(5, &bump);
614    /// s.push_str("hello");
615    ///
616    /// s.truncate(2);
617    ///
618    /// assert_eq!(s, "he");
619    /// ```
620    #[inline]
621    pub fn truncate(&mut self, new_len: usize) {
622        self.initialized.truncate(new_len);
623    }
624
625    /// Removes a [`char`] from this string at a byte position and returns it.
626    ///
627    /// This is an *O*(*n*) operation, as it requires copying every element in the
628    /// buffer.
629    ///
630    /// # Panics
631    ///
632    /// Panics if `idx` is larger than or equal to the string's length,
633    /// or if it does not lie on a [`char`] boundary.
634    ///
635    /// # Examples
636    ///
637    /// ```
638    /// # use bump_scope::{Bump, FixedBumpString};
639    /// # let bump: Bump = Bump::new();
640    /// let mut s = FixedBumpString::with_capacity_in(4, &bump);
641    /// s.push_str("abç");
642    ///
643    /// assert_eq!(s.remove(0), 'a');
644    /// assert_eq!(s.remove(1), 'ç');
645    /// assert_eq!(s.remove(0), 'b');
646    /// ```
647    #[inline]
648    pub fn remove(&mut self, idx: usize) -> char {
649        self.initialized.remove(idx)
650    }
651
652    /// Retains only the characters specified by the predicate.
653    ///
654    /// In other words, remove all characters `c` such that `f(c)` returns `false`.
655    /// This method operates in place, visiting each character exactly once in the
656    /// original order, and preserves the order of the retained characters.
657    ///
658    /// # Examples
659    ///
660    /// ```
661    /// # use bump_scope::{Bump, FixedBumpString};
662    /// # let bump: Bump = Bump::new();
663    /// let mut s = FixedBumpString::with_capacity_in(50, &bump);
664    /// s.push_str("f_o_ob_ar");
665    ///
666    /// s.retain(|c| c != '_');
667    ///
668    /// assert_eq!(s, "foobar");
669    /// ```
670    ///
671    /// Because the elements are visited exactly once in the original order,
672    /// external state may be used to decide which elements to keep.
673    ///
674    /// ```
675    /// # use bump_scope::{Bump, FixedBumpString};
676    /// # let bump: Bump = Bump::new();
677    /// let mut s = FixedBumpString::with_capacity_in(50, &bump);
678    /// s.push_str("abcde");
679    ///
680    /// let keep = [false, true, true, false, true];
681    /// let mut iter = keep.iter();
682    /// s.retain(|_| *iter.next().unwrap());
683    /// assert_eq!(s, "bce");
684    /// ```
685    #[inline]
686    pub fn retain<F>(&mut self, f: F)
687    where
688        F: FnMut(char) -> bool,
689    {
690        self.initialized.retain(f);
691    }
692
693    /// Removes the specified range from the string in bulk, returning all
694    /// removed characters as an iterator.
695    ///
696    /// The returned iterator keeps a mutable borrow on the string to optimize
697    /// its implementation.
698    ///
699    /// # Panics
700    ///
701    /// Panics if the starting point or end point do not lie on a [`char`]
702    /// boundary, or if they're out of bounds.
703    ///
704    /// # Leaking
705    ///
706    /// If the returned iterator goes out of scope without being dropped (due to
707    /// [`core::mem::forget`], for example), the string may still contain a copy
708    /// of any drained characters, or may have lost characters arbitrarily,
709    /// including characters outside the range.
710    ///
711    /// # Examples
712    ///
713    /// Basic usage:
714    ///
715    /// ```
716    /// # use bump_scope::{Bump, FixedBumpString};
717    /// # let bump: Bump = Bump::new();
718    /// let mut s = FixedBumpString::with_capacity_in(50, &bump);
719    /// s.push_str("α is alpha, β is beta");
720    ///
721    /// let beta_offset = s.find('β').unwrap_or(s.len());
722    ///
723    /// // Remove the range up until the β from the string
724    /// let t: String = s.drain(..beta_offset).collect();
725    /// assert_eq!(t, "α is alpha, ");
726    /// assert_eq!(s, "β is beta");
727    ///
728    /// // A full range clears the string, like `clear()` does
729    /// s.drain(..);
730    /// assert_eq!(s, "");
731    /// ```
732    pub fn drain<R>(&mut self, range: R) -> owned_str::Drain<'_>
733    where
734        R: RangeBounds<usize>,
735    {
736        self.initialized.drain(range)
737    }
738
739    /// Extracts a string slice containing the entire `FixedBumpString`.
740    #[must_use]
741    #[inline(always)]
742    pub fn as_str(&self) -> &str {
743        &self.initialized
744    }
745
746    /// Converts a `FixedBumpString` into a mutable string slice.
747    #[must_use]
748    #[inline(always)]
749    pub fn as_mut_str(&mut self) -> &mut str {
750        &mut self.initialized
751    }
752
753    /// Returns a `NonNull` pointer to the string's buffer, or a dangling
754    /// `NonNull` pointer valid for zero sized reads if the string didn't allocate.
755    ///
756    /// The caller must ensure that the string outlives the pointer this
757    /// function returns, or else it will end up dangling.
758    /// Modifying the string may cause its buffer to be reallocated,
759    /// which would also make any pointers to it invalid.
760    ///
761    /// This method guarantees that for the purpose of the aliasing model, this method
762    /// does not materialize a reference to the underlying slice, and thus the returned pointer
763    /// will remain valid when mixed with other calls to [`as_ptr`], [`as_mut_ptr`],
764    /// and [`as_non_null`].
765    /// Note that calling other methods that materialize references to the slice,
766    /// or references to specific elements you are planning on accessing through this pointer,
767    /// may still invalidate this pointer.
768    /// See the second example below for how this guarantee can be used.
769    ///
770    /// # Examples
771    ///
772    /// ```
773    /// # use bump_scope::{Bump, FixedBumpString};
774    /// # let bump: Bump = Bump::new();
775    /// // Allocate vector big enough for 4 elements.
776    /// let size = 4;
777    /// let mut x = FixedBumpString::with_capacity_in(size, &bump);
778    /// let x_ptr = x.as_non_null();
779    ///
780    /// // Initialize elements via raw pointer writes, then set length.
781    /// unsafe {
782    ///     for i in 0..size {
783    ///         x_ptr.add(i).write(i as u8 + b'a');
784    ///     }
785    ///     x.as_mut_vec().set_len(size);
786    /// }
787    /// assert_eq!(&*x, "abcd");
788    /// ```
789    ///
790    /// Due to the aliasing guarantee, the following code is legal:
791    ///
792    /// ```
793    /// # use bump_scope::{Bump, bump_format};
794    /// # let bump: Bump = Bump::new();
795    /// unsafe {
796    ///     let v = bump_format!(in &bump, "a").into_fixed_string();
797    ///     let ptr1 = v.as_non_null();
798    ///     ptr1.write(b'b');
799    ///     let ptr2 = v.as_non_null();
800    ///     ptr2.write(b'c');
801    ///     // Notably, the write to `ptr2` did *not* invalidate `ptr1`:
802    ///     ptr1.write(b'd');
803    /// }
804    /// ```
805    ///
806    /// [`as_mut_ptr`]: Self::as_mut_ptr
807    /// [`as_ptr`]: Self::as_ptr
808    /// [`as_non_null`]: Self::as_non_null
809    #[must_use]
810    #[inline(always)]
811    pub const fn as_non_null(&self) -> NonNull<u8> {
812        self.initialized.as_non_null()
813    }
814
815    /// Returns a byte slice of this `FixedBumpString`'s contents.
816    #[must_use]
817    #[inline(always)]
818    pub fn as_bytes(&self) -> &[u8] {
819        self.initialized.as_bytes()
820    }
821
822    /// Returns a mutable reference to the contents of this `FixedBumpString`.
823    ///
824    /// # Safety
825    ///
826    /// This function is unsafe because the returned `&mut FixedBumpVec<u8>` allows writing
827    /// bytes which are not valid UTF-8. If this constraint is violated, using
828    /// the original `FixedBumpString` after dropping the `&mut FixedBumpVec<u8>` may violate memory
829    /// safety, as `FixedBumpString`s must be valid UTF-8.
830    #[must_use]
831    #[inline(always)]
832    pub unsafe fn as_mut_vec(&mut self) -> &mut FixedBumpVec<'a, u8> {
833        unsafe {
834            // SAFETY: `FixedBumpVec<u8>` and `FixedBumpString` have the same representation;
835            // only the invariant that the bytes are utf8 is different.
836            transmute_mut(self)
837        }
838    }
839
840    /// Returns a raw pointer to the slice, or a dangling raw pointer
841    /// valid for zero sized reads.
842    #[inline]
843    #[must_use]
844    pub fn as_ptr(&self) -> *const u8 {
845        self.initialized.as_ptr()
846    }
847
848    /// Returns an unsafe mutable pointer to slice, or a dangling
849    /// raw pointer valid for zero sized reads.
850    #[inline]
851    pub fn as_mut_ptr(&mut self) -> *mut u8 {
852        self.initialized.as_mut_ptr()
853    }
854
855    #[inline(always)]
856    pub(crate) unsafe fn set_ptr(&mut self, new_ptr: NonNull<u8>) {
857        unsafe { self.initialized.set_ptr(new_ptr) };
858    }
859
860    #[inline(always)]
861    pub(crate) unsafe fn set_len(&mut self, new_len: usize) {
862        unsafe { self.initialized.set_len(new_len) };
863    }
864
865    #[inline(always)]
866    pub(crate) unsafe fn set_cap(&mut self, new_cap: usize) {
867        self.capacity = new_cap;
868    }
869}
870
871impl FixedBumpString<'_> {
872    /// Appends the given [`char`] to the end of this string.
873    ///
874    /// # Panics
875    /// Panics if the string does not have enough capacity.
876    ///
877    /// # Examples
878    /// ```
879    /// # use bump_scope::{Bump, FixedBumpString};
880    /// # let bump: Bump = Bump::new();
881    /// let mut s = FixedBumpString::with_capacity_in(3, &bump);
882    ///
883    /// s.push('a');
884    /// s.push('b');
885    /// s.push('c');
886    ///
887    /// assert_eq!(s, "abc");
888    /// ```
889    #[inline(always)]
890    #[cfg(feature = "panic-on-alloc")]
891    pub fn push(&mut self, ch: char) {
892        panic_on_error(self.generic_push(ch));
893    }
894
895    /// Appends the given [`char`] to the end of this string.
896    ///
897    /// # Errors
898    /// Errors if the string does not have enough capacity.
899    ///
900    /// # Examples
901    /// ```
902    /// # use bump_scope::{Bump, FixedBumpString};
903    /// # let bump: Bump = Bump::new();
904    /// let mut s = FixedBumpString::try_with_capacity_in(3, &bump)?;
905    ///
906    /// s.try_push('a')?;
907    /// s.try_push('b')?;
908    /// s.try_push('c')?;
909    ///
910    /// assert_eq!(s, "abc");
911    /// # Ok::<(), bump_scope::alloc::AllocError>(())
912    /// ```
913    #[inline(always)]
914    pub fn try_push(&mut self, ch: char) -> Result<(), AllocError> {
915        self.generic_push(ch)
916    }
917
918    #[inline]
919    pub(crate) fn generic_push<E: ErrorBehavior>(&mut self, ch: char) -> Result<(), E> {
920        let vec = unsafe { self.as_mut_vec() };
921
922        match ch.len_utf8() {
923            1 => vec.generic_push(ch as u8),
924            _ => vec.generic_extend_from_slice_copy(ch.encode_utf8(&mut [0; 4]).as_bytes()),
925        }
926    }
927
928    /// Appends a given string slice onto the end of this string.
929    ///
930    /// # Panics
931    /// Panics if the string does not have enough capacity.
932    ///
933    /// # Examples
934    /// ```
935    /// # use bump_scope::{Bump, FixedBumpString};
936    /// # let bump: Bump = Bump::new();
937    /// let mut s = FixedBumpString::with_capacity_in(6, &bump);
938    ///
939    /// s.push_str("foo");
940    /// s.push_str("bar");
941    ///
942    /// assert_eq!(s, "foobar");
943    /// ```
944    #[inline(always)]
945    #[cfg(feature = "panic-on-alloc")]
946    pub fn push_str(&mut self, string: &str) {
947        panic_on_error(self.generic_push_str(string));
948    }
949
950    /// Appends a given string slice onto the end of this string.
951    ///
952    /// # Errors
953    /// Errors if the string does not have enough capacity.
954    ///
955    /// # Examples
956    /// ```
957    /// # use bump_scope::{Bump, FixedBumpString};
958    /// # let bump: Bump = Bump::new();
959    /// let mut s = FixedBumpString::try_with_capacity_in(6, &bump)?;
960    ///
961    /// s.try_push_str("foo")?;
962    /// s.try_push_str("bar")?;
963    ///
964    /// assert_eq!(s, "foobar");
965    /// # Ok::<(), bump_scope::alloc::AllocError>(())
966    /// ```
967    #[inline(always)]
968    pub fn try_push_str(&mut self, string: &str) -> Result<(), AllocError> {
969        self.generic_push_str(string)
970    }
971
972    #[inline]
973    pub(crate) fn generic_push_str<E: ErrorBehavior>(&mut self, string: &str) -> Result<(), E> {
974        let vec = unsafe { self.as_mut_vec() };
975        vec.generic_extend_from_slice_copy(string.as_bytes())
976    }
977
978    /// Inserts a character into this string at a byte position.
979    ///
980    /// This is an *O*(*n*) operation as it requires copying every element in the
981    /// buffer.
982    ///
983    /// # Panics
984    /// Panics if the string does not have enough capacity.
985    ///
986    /// Panics if `idx` is larger than the string's length, or if it does not
987    /// lie on a [`char`] boundary.
988    ///
989    /// # Examples
990    /// ```
991    /// # use bump_scope::{Bump, FixedBumpString};
992    /// # let bump: Bump = Bump::new();
993    /// let mut s = FixedBumpString::with_capacity_in(3, &bump);
994    ///
995    /// s.insert(0, 'f');
996    /// s.insert(1, 'o');
997    /// s.insert(2, 'o');
998    ///
999    /// assert_eq!("foo", s);
1000    /// ```
1001    #[inline(always)]
1002    #[cfg(feature = "panic-on-alloc")]
1003    pub fn insert(&mut self, idx: usize, ch: char) {
1004        panic_on_error(self.generic_insert(idx, ch));
1005    }
1006
1007    /// Inserts a character into this string at a byte position.
1008    ///
1009    /// This is an *O*(*n*) operation as it requires copying every element in the
1010    /// buffer.
1011    ///
1012    /// # Panics
1013    /// Panics if `idx` is larger than the string's length, or if it does not
1014    /// lie on a [`char`] boundary.
1015    ///
1016    /// # Errors
1017    /// Errors if the string does not have enough capacity.
1018    ///
1019    /// # Examples
1020    /// ```
1021    /// # use bump_scope::{Bump, FixedBumpString};
1022    /// # let bump: Bump = Bump::new();
1023    /// let mut s = FixedBumpString::try_with_capacity_in(3, &bump)?;
1024    ///
1025    /// s.try_insert(0, 'f')?;
1026    /// s.try_insert(1, 'o')?;
1027    /// s.try_insert(2, 'o')?;
1028    ///
1029    /// assert_eq!("foo", s);
1030    /// # Ok::<(), bump_scope::alloc::AllocError>(())
1031    /// ```
1032    #[inline(always)]
1033    pub fn try_insert(&mut self, idx: usize, ch: char) -> Result<(), AllocError> {
1034        self.generic_insert(idx, ch)
1035    }
1036
1037    #[inline]
1038    pub(crate) fn generic_insert<E: ErrorBehavior>(&mut self, idx: usize, ch: char) -> Result<(), E> {
1039        self.assert_char_boundary(idx);
1040        let mut bits = [0; 4];
1041        let bits = ch.encode_utf8(&mut bits).as_bytes();
1042
1043        unsafe { self.insert_bytes(idx, bits) }
1044    }
1045
1046    /// Inserts a string slice into this string at a byte position.
1047    ///
1048    /// This is an *O*(*n*) operation as it requires copying every element in the
1049    /// buffer.
1050    ///
1051    /// # Panics
1052    /// Panics if the string does not have enough capacity.
1053    ///
1054    /// Panics if `idx` is larger than the string's length, or if it does not
1055    /// lie on a [`char`] boundary.
1056    ///
1057    /// # Examples
1058    /// ```
1059    /// # use bump_scope::{Bump, FixedBumpString};
1060    /// # let bump: Bump = Bump::new();
1061    /// let mut s = FixedBumpString::with_capacity_in(6, &bump);
1062    /// s.push_str("bar");
1063    ///
1064    /// s.insert_str(0, "foo");
1065    ///
1066    /// assert_eq!("foobar", s);
1067    /// ```
1068    #[inline(always)]
1069    #[cfg(feature = "panic-on-alloc")]
1070    pub fn insert_str(&mut self, idx: usize, string: &str) {
1071        panic_on_error(self.generic_insert_str(idx, string));
1072    }
1073
1074    /// Inserts a string slice into this string at a byte position.
1075    ///
1076    /// This is an *O*(*n*) operation as it requires copying every element in the
1077    /// buffer.
1078    ///
1079    /// # Panics
1080    /// Panics if `idx` is larger than the string's length, or if it does not
1081    /// lie on a [`char`] boundary.
1082    ///
1083    /// # Errors
1084    /// Errors if the string does not have enough capacity.
1085    ///
1086    /// # Examples
1087    /// ```
1088    /// # use bump_scope::{Bump, FixedBumpString};
1089    /// # let bump: Bump = Bump::new();
1090    /// let mut s = FixedBumpString::try_with_capacity_in(6, &bump)?;
1091    /// s.try_push_str("bar")?;
1092    ///
1093    /// s.try_insert_str(0, "foo")?;
1094    ///
1095    /// assert_eq!("foobar", s);
1096    /// # Ok::<(), bump_scope::alloc::AllocError>(())
1097    /// ```
1098    #[inline(always)]
1099    pub fn try_insert_str(&mut self, idx: usize, string: &str) -> Result<(), AllocError> {
1100        self.generic_insert_str(idx, string)
1101    }
1102
1103    #[inline]
1104    pub(crate) fn generic_insert_str<E: ErrorBehavior>(&mut self, idx: usize, string: &str) -> Result<(), E> {
1105        self.assert_char_boundary(idx);
1106        unsafe { self.insert_bytes(idx, string.as_bytes()) }
1107    }
1108
1109    /// Copies elements from `src` range to the end of the string.
1110    ///
1111    /// # Panics
1112    /// Panics if the string does not have enough capacity.
1113    ///
1114    /// Panics if the starting point or end point do not lie on a [`char`]
1115    /// boundary, or if they're out of bounds.
1116    ///
1117    /// # Examples
1118    /// ```
1119    /// # use bump_scope::{Bump, FixedBumpString};
1120    /// # let bump: Bump = Bump::new();
1121    /// let mut string = FixedBumpString::with_capacity_in(14, &bump);
1122    /// string.push_str("abcde");
1123    ///
1124    /// string.extend_from_within(2..);
1125    /// assert_eq!(string, "abcdecde");
1126    ///
1127    /// string.extend_from_within(..2);
1128    /// assert_eq!(string, "abcdecdeab");
1129    ///
1130    /// string.extend_from_within(4..8);
1131    /// assert_eq!(string, "abcdecdeabecde");
1132    /// ```
1133    #[inline(always)]
1134    #[cfg(feature = "panic-on-alloc")]
1135    pub fn extend_from_within<R>(&mut self, src: R)
1136    where
1137        R: RangeBounds<usize>,
1138    {
1139        panic_on_error(self.generic_extend_from_within(src));
1140    }
1141
1142    /// Copies elements from `src` range to the end of the string.
1143    ///
1144    /// # Panics
1145    /// Panics if the starting point or end point do not lie on a [`char`]
1146    /// boundary, or if they're out of bounds.
1147    ///
1148    /// # Errors
1149    /// Errors if the string does not have enough capacity.
1150    ///
1151    /// # Examples
1152    /// ```
1153    /// # use bump_scope::{Bump, FixedBumpString};
1154    /// # let bump: Bump = Bump::new();
1155    /// let mut string = FixedBumpString::try_with_capacity_in(14, &bump)?;
1156    /// string.try_push_str("abcde")?;
1157    ///
1158    /// string.try_extend_from_within(2..)?;
1159    /// assert_eq!(string, "abcdecde");
1160    ///
1161    /// string.try_extend_from_within(..2)?;
1162    /// assert_eq!(string, "abcdecdeab");
1163    ///
1164    /// string.try_extend_from_within(4..8)?;
1165    /// assert_eq!(string, "abcdecdeabecde");
1166    /// # Ok::<(), bump_scope::alloc::AllocError>(())
1167    /// ```
1168    #[inline(always)]
1169    pub fn try_extend_from_within<R>(&mut self, src: R) -> Result<(), AllocError>
1170    where
1171        R: RangeBounds<usize>,
1172    {
1173        self.generic_extend_from_within(src)
1174    }
1175
1176    #[inline]
1177    pub(crate) fn generic_extend_from_within<E: ErrorBehavior, R: RangeBounds<usize>>(&mut self, src: R) -> Result<(), E> {
1178        let src @ Range { start, end } = polyfill::slice::range(src, ..self.len());
1179
1180        self.assert_char_boundary(start);
1181        self.assert_char_boundary(end);
1182
1183        let vec = unsafe { self.as_mut_vec() };
1184        vec.generic_extend_from_within_copy(src)
1185    }
1186
1187    /// Extends this string by pushing `additional` new zero bytes.
1188    ///
1189    /// # Panics
1190    /// Panics if the string does not have enough capacity.
1191    ///
1192    /// # Examples
1193    /// ```
1194    /// # use bump_scope::{Bump, FixedBumpString};
1195    /// # let bump: Bump = Bump::new();
1196    /// let mut string = FixedBumpString::with_capacity_in(8, &bump);
1197    /// string.push_str("What?");
1198    /// string.extend_zeroed(3);
1199    /// assert_eq!(string, "What?\0\0\0");
1200    /// ```
1201    #[inline(always)]
1202    #[cfg(feature = "panic-on-alloc")]
1203    pub fn extend_zeroed(&mut self, additional: usize) {
1204        panic_on_error(self.generic_extend_zeroed(additional));
1205    }
1206
1207    /// Extends this string by pushing `additional` new zero bytes.
1208    ///
1209    /// # Errors
1210    /// Errors if the string does not have enough capacity.
1211    ///
1212    /// # Examples
1213    /// ```
1214    /// # use bump_scope::{Bump, FixedBumpString};
1215    /// # let bump: Bump = Bump::new();
1216    /// let mut string = FixedBumpString::try_with_capacity_in(8, &bump)?;
1217    /// string.try_push_str("What?")?;
1218    /// string.try_extend_zeroed(3)?;
1219    /// assert_eq!(string, "What?\0\0\0");
1220    /// # Ok::<(), bump_scope::alloc::AllocError>(())
1221    /// ```
1222    #[inline(always)]
1223    pub fn try_extend_zeroed(&mut self, additional: usize) -> Result<(), AllocError> {
1224        self.generic_extend_zeroed(additional)
1225    }
1226
1227    #[inline]
1228    pub(crate) fn generic_extend_zeroed<E: ErrorBehavior>(&mut self, additional: usize) -> Result<(), E> {
1229        let vec = unsafe { self.as_mut_vec() };
1230
1231        vec.generic_reserve(additional)?;
1232
1233        unsafe {
1234            let ptr = vec.as_mut_ptr();
1235            let len = vec.len();
1236
1237            ptr.add(len).write_bytes(0, additional);
1238            vec.set_len(len + additional);
1239        }
1240
1241        Ok(())
1242    }
1243
1244    /// Removes the specified range in the string,
1245    /// and replaces it with the given string.
1246    /// The given string doesn't need to be the same length as the range.
1247    ///
1248    /// # Panics
1249    /// Panics if the string does not have enough capacity.
1250    ///
1251    /// Panics if the starting point or end point do not lie on a [`char`]
1252    /// boundary, or if they're out of bounds.
1253    ///
1254    /// # Examples
1255    /// ```
1256    /// # use bump_scope::{Bump, FixedBumpString};
1257    /// # let bump: Bump = Bump::new();
1258    /// let mut s = FixedBumpString::with_capacity_in(50, &bump);
1259    /// s.push_str("α is alpha, β is beta");
1260    /// let beta_offset = s.find('β').unwrap_or(s.len());
1261    ///
1262    /// // Replace the range up until the β from the string
1263    /// s.replace_range(..beta_offset, "Α is capital alpha; ");
1264    /// assert_eq!(s, "Α is capital alpha; β is beta");
1265    /// ```
1266    #[inline(always)]
1267    #[cfg(feature = "panic-on-alloc")]
1268    pub fn replace_range<R>(&mut self, range: R, replace_with: &str)
1269    where
1270        R: RangeBounds<usize>,
1271    {
1272        panic_on_error(self.generic_replace_range(range, replace_with));
1273    }
1274
1275    /// Removes the specified range in the string,
1276    /// and replaces it with the given string.
1277    /// The given string doesn't need to be the same length as the range.
1278    ///
1279    /// # Panics
1280    /// Panics if the starting point or end point do not lie on a [`char`]
1281    /// boundary, or if they're out of bounds.
1282    ///
1283    /// # Errors
1284    /// Errors if the string does not have enough capacity.
1285    ///
1286    /// # Examples
1287    /// ```
1288    /// # use bump_scope::{Bump, FixedBumpString};
1289    /// # let bump: Bump = Bump::new();
1290    /// let mut s = FixedBumpString::try_with_capacity_in(50, &bump)?;
1291    /// s.push_str("α is alpha, β is beta");
1292    /// let beta_offset = s.find('β').unwrap_or(s.len());
1293    ///
1294    /// // Replace the range up until the β from the string
1295    /// s.try_replace_range(..beta_offset, "Α is capital alpha; ")?;
1296    /// assert_eq!(s, "Α is capital alpha; β is beta");
1297    ///
1298    /// // An error will be returned when the capacity does not suffice
1299    /// let mut s = FixedBumpString::try_with_capacity_in(5, &bump)?;
1300    /// s.push_str("hello");
1301    /// assert!(s.try_replace_range(4..=4, " n").is_err());
1302    /// # Ok::<(), bump_scope::alloc::AllocError>(())
1303    /// ```
1304    #[inline(always)]
1305    pub fn try_replace_range<R>(&mut self, range: R, replace_with: &str) -> Result<(), AllocError>
1306    where
1307        R: RangeBounds<usize>,
1308    {
1309        self.generic_replace_range(range, replace_with)
1310    }
1311
1312    #[inline]
1313    pub(crate) fn generic_replace_range<E: ErrorBehavior, R: RangeBounds<usize>>(
1314        &mut self,
1315        range: R,
1316        replace_with: &str,
1317    ) -> Result<(), E> {
1318        let Range { start, end } = polyfill::slice::range(range, ..self.len());
1319
1320        self.assert_char_boundary(start);
1321        self.assert_char_boundary(end);
1322
1323        let range_len = end - start;
1324        let given_len = replace_with.len();
1325
1326        let additional_len = given_len.saturating_sub(range_len);
1327        self.generic_reserve(additional_len)?;
1328
1329        // move the tail
1330        if range_len != given_len {
1331            unsafe {
1332                let src = self.as_ptr().add(end);
1333                let dst = self.as_mut_ptr().add(start + given_len);
1334                let len = self.len() - end;
1335                src.copy_to(dst, len);
1336            }
1337        }
1338
1339        // fill with given string
1340        unsafe {
1341            let src = replace_with.as_ptr();
1342            let dst = self.as_mut_ptr().add(start);
1343            let len = replace_with.len();
1344            src.copy_to_nonoverlapping(dst, len);
1345        }
1346
1347        // update len
1348        #[expect(clippy::cast_sign_loss, clippy::cast_possible_wrap)]
1349        unsafe {
1350            // Casting to `isize` is fine because per `Layout`'s rules all the `*len`s must be
1351            // less than isize::MAX. Subtracting two positive `isize`s can't overflow.
1352            let len_diff = given_len as isize - range_len as isize;
1353            self.set_len((self.len() as isize + len_diff) as usize);
1354        }
1355
1356        Ok(())
1357    }
1358
1359    /// Checks if at least `additional` more bytes can be inserted
1360    /// in the given `FixedBumpString` due to capacity.
1361    ///
1362    /// # Panics
1363    /// Panics if the string does not have enough capacity.
1364    #[inline(always)]
1365    #[cfg(feature = "panic-on-alloc")]
1366    pub fn reserve(&mut self, additional: usize) {
1367        panic_on_error(self.generic_reserve(additional));
1368    }
1369
1370    /// Checks if at least `additional` more bytes can be inserted
1371    /// in the given `FixedBumpString` due to capacity.
1372    ///
1373    /// # Errors
1374    /// Errors if the string does not have enough capacity.
1375    #[inline(always)]
1376    pub fn try_reserve(&mut self, additional: usize) -> Result<(), AllocError> {
1377        self.generic_reserve(additional)
1378    }
1379
1380    #[inline]
1381    pub(crate) fn generic_reserve<E: ErrorBehavior>(&mut self, additional: usize) -> Result<(), E> {
1382        let vec = unsafe { self.as_mut_vec() };
1383        vec.generic_reserve(additional)
1384    }
1385
1386    unsafe fn insert_bytes<B: ErrorBehavior>(&mut self, idx: usize, bytes: &[u8]) -> Result<(), B> {
1387        unsafe {
1388            let vec = self.as_mut_vec();
1389
1390            let len = vec.len();
1391            let amt = bytes.len();
1392            vec.generic_reserve(amt)?;
1393
1394            ptr::copy(vec.as_ptr().add(idx), vec.as_mut_ptr().add(idx + amt), len - idx);
1395            ptr::copy_nonoverlapping(bytes.as_ptr(), vec.as_mut_ptr().add(idx), amt);
1396            vec.set_len(len + amt);
1397
1398            Ok(())
1399        }
1400    }
1401}
1402
1403impl fmt::Write for FixedBumpString<'_> {
1404    #[inline(always)]
1405    fn write_str(&mut self, s: &str) -> fmt::Result {
1406        self.try_push_str(s).map_err(|_| fmt::Error)
1407    }
1408
1409    #[inline(always)]
1410    fn write_char(&mut self, c: char) -> fmt::Result {
1411        self.try_push(c).map_err(|_| fmt::Error)
1412    }
1413}
1414
1415impl Debug for FixedBumpString<'_> {
1416    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1417        Debug::fmt(self.as_str(), f)
1418    }
1419}
1420
1421impl Display for FixedBumpString<'_> {
1422    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1423        Display::fmt(self.as_str(), f)
1424    }
1425}
1426
1427impl Default for FixedBumpString<'_> {
1428    fn default() -> Self {
1429        Self::new()
1430    }
1431}
1432
1433impl Deref for FixedBumpString<'_> {
1434    type Target = str;
1435
1436    #[inline]
1437    fn deref(&self) -> &Self::Target {
1438        self.as_str()
1439    }
1440}
1441
1442impl DerefMut for FixedBumpString<'_> {
1443    #[inline]
1444    fn deref_mut(&mut self) -> &mut Self::Target {
1445        self.as_mut_str()
1446    }
1447}
1448
1449#[cfg(feature = "panic-on-alloc")]
1450impl core::ops::AddAssign<&str> for FixedBumpString<'_> {
1451    #[inline]
1452    fn add_assign(&mut self, rhs: &str) {
1453        self.push_str(rhs);
1454    }
1455}
1456
1457impl AsRef<str> for FixedBumpString<'_> {
1458    #[inline]
1459    fn as_ref(&self) -> &str {
1460        self.as_str()
1461    }
1462}
1463
1464impl AsMut<str> for FixedBumpString<'_> {
1465    #[inline]
1466    fn as_mut(&mut self) -> &mut str {
1467        self.as_mut_str()
1468    }
1469}
1470
1471impl Borrow<str> for FixedBumpString<'_> {
1472    #[inline]
1473    fn borrow(&self) -> &str {
1474        self.as_str()
1475    }
1476}
1477
1478impl BorrowMut<str> for FixedBumpString<'_> {
1479    #[inline]
1480    fn borrow_mut(&mut self) -> &mut str {
1481        self.as_mut_str()
1482    }
1483}
1484
1485impl PartialEq for FixedBumpString<'_> {
1486    #[inline]
1487    fn eq(&self, other: &Self) -> bool {
1488        <str as PartialEq>::eq(self, other)
1489    }
1490
1491    #[inline]
1492    fn ne(&self, other: &Self) -> bool {
1493        <str as PartialEq>::ne(self, other)
1494    }
1495}
1496
1497macro_rules! impl_partial_eq {
1498    (
1499        $(
1500            $(#[$attr:meta])*
1501            $string_like:ty,
1502        )*
1503    ) => {
1504        $(
1505            $(#[$attr])*
1506            impl<'a> PartialEq<$string_like> for FixedBumpString<'a> {
1507                #[inline]
1508                fn eq(&self, other: &$string_like) -> bool {
1509                    <str as PartialEq>::eq(self, other)
1510                }
1511
1512                #[inline]
1513                fn ne(&self, other: &$string_like) -> bool {
1514                    <str as PartialEq>::ne(self, other)
1515                }
1516            }
1517
1518            $(#[$attr])*
1519            impl<'a> PartialEq<FixedBumpString<'a>> for $string_like {
1520                #[inline]
1521                fn eq(&self, other: &FixedBumpString<'a>) -> bool {
1522                    <str as PartialEq>::eq(self, other)
1523                }
1524
1525                #[inline]
1526                fn ne(&self, other: &FixedBumpString<'a>) -> bool {
1527                    <str as PartialEq>::ne(self, other)
1528                }
1529            }
1530        )*
1531    };
1532}
1533
1534impl_partial_eq! {
1535    str,
1536
1537    &str,
1538
1539    #[cfg(feature = "alloc")]
1540    alloc_crate::string::String,
1541
1542    #[cfg(feature = "alloc")]
1543    alloc_crate::borrow::Cow<'_, str>,
1544}
1545
1546impl Eq for FixedBumpString<'_> {}
1547
1548impl PartialOrd for FixedBumpString<'_> {
1549    #[inline]
1550    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
1551        Some(self.cmp(other))
1552    }
1553
1554    #[inline]
1555    fn lt(&self, other: &Self) -> bool {
1556        <str as PartialOrd>::lt(self, other)
1557    }
1558
1559    #[inline]
1560    fn le(&self, other: &Self) -> bool {
1561        <str as PartialOrd>::le(self, other)
1562    }
1563
1564    #[inline]
1565    fn gt(&self, other: &Self) -> bool {
1566        <str as PartialOrd>::gt(self, other)
1567    }
1568
1569    #[inline]
1570    fn ge(&self, other: &Self) -> bool {
1571        <str as PartialOrd>::ge(self, other)
1572    }
1573}
1574
1575impl Ord for FixedBumpString<'_> {
1576    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
1577        <str as Ord>::cmp(self, other)
1578    }
1579}
1580
1581impl Hash for FixedBumpString<'_> {
1582    #[inline]
1583    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
1584        self.as_str().hash(state);
1585    }
1586}
1587
1588#[cfg(feature = "panic-on-alloc")]
1589impl<'s> Extend<&'s str> for FixedBumpString<'_> {
1590    #[inline]
1591    fn extend<T: IntoIterator<Item = &'s str>>(&mut self, iter: T) {
1592        for str in iter {
1593            self.push_str(str);
1594        }
1595    }
1596}
1597
1598#[cfg(feature = "panic-on-alloc")]
1599impl Extend<char> for FixedBumpString<'_> {
1600    fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
1601        let iterator = iter.into_iter();
1602        let (lower_bound, _) = iterator.size_hint();
1603        self.reserve(lower_bound);
1604        iterator.for_each(move |c| self.push(c));
1605    }
1606}
1607
1608#[cfg(feature = "panic-on-alloc")]
1609impl<'s> Extend<&'s char> for FixedBumpString<'_> {
1610    fn extend<I: IntoIterator<Item = &'s char>>(&mut self, iter: I) {
1611        self.extend(iter.into_iter().copied());
1612    }
1613}
1614
1615#[cfg(feature = "alloc")]
1616impl<'a> From<FixedBumpString<'a>> for alloc_crate::string::String {
1617    #[inline]
1618    fn from(value: FixedBumpString<'a>) -> Self {
1619        value.as_str().into()
1620    }
1621}
1622
1623impl NoDrop for FixedBumpString<'_> {}