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