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<'_> {}