compact_str/lib.rs
1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![no_std]
4
5#[cfg(feature = "std")]
6#[macro_use]
7extern crate std;
8
9#[cfg_attr(test, macro_use)]
10extern crate alloc;
11
12use alloc::borrow::Cow;
13use alloc::boxed::Box;
14use alloc::string::String;
15use castaway::match_type;
16#[doc(hidden)] // Referenced in macros.
17pub use core;
18use core::borrow::{Borrow, BorrowMut};
19use core::cmp::Ordering;
20use core::hash::{Hash, Hasher};
21use core::iter::FusedIterator;
22use core::ops::{Add, AddAssign, Bound, Deref, DerefMut, RangeBounds};
23use core::str::{FromStr, Utf8Error};
24use core::{fmt, mem, slice};
25#[cfg(feature = "std")]
26use std::ffi::OsStr;
27
28mod features;
29mod macros;
30mod unicode_data;
31
32mod repr;
33use repr::Repr;
34
35mod traits;
36pub use traits::{CompactStringExt, ToCompactString};
37
38#[cfg(test)]
39mod tests;
40
41/// A [`CompactString`] is a compact string type that can be used almost anywhere a
42/// [`String`] or [`str`] can be used.
43///
44/// ## Using `CompactString`
45/// ```
46/// use compact_str::CompactString;
47/// # use std::collections::HashMap;
48///
49/// // CompactString auto derefs into a str so you can use all methods from `str`
50/// // that take a `&self`
51/// if CompactString::new("hello world!").is_ascii() {
52/// println!("we're all ASCII")
53/// }
54///
55/// // You can use a CompactString in collections like you would a String or &str
56/// let mut map: HashMap<CompactString, CompactString> = HashMap::new();
57///
58/// // directly construct a new `CompactString`
59/// map.insert(CompactString::new("nyc"), CompactString::new("empire state building"));
60/// // create a `CompactString` from a `&str`
61/// map.insert("sf".into(), "transamerica pyramid".into());
62/// // create a `CompactString` from a `String`
63/// map.insert(String::from("sea").into(), String::from("space needle").into());
64///
65/// fn wrapped_print<T: AsRef<str>>(text: T) {
66/// println!("{}", text.as_ref());
67/// }
68///
69/// // CompactString impls AsRef<str> and Borrow<str>, so it can be used anywhere
70/// // that expects a generic string
71/// if let Some(building) = map.get("nyc") {
72/// wrapped_print(building);
73/// }
74///
75/// // CompactString can also be directly compared to a String or &str
76/// assert_eq!(CompactString::new("chicago"), "chicago");
77/// assert_eq!(CompactString::new("houston"), String::from("houston"));
78/// ```
79///
80/// # Converting from a `String`
81/// It's important that a `CompactString` interops well with `String`, so you can easily use both in
82/// your code base.
83///
84/// `CompactString` implements `From<String>` and operates in the following manner:
85/// - Eagerly inlines the string, possibly dropping excess capacity
86/// - Otherwise re-uses the same underlying buffer from `String`
87///
88/// ```
89/// use compact_str::CompactString;
90///
91/// // eagerly inlining
92/// let short = String::from("hello world");
93/// let short_c = CompactString::from(short);
94/// assert!(!short_c.is_heap_allocated());
95///
96/// // dropping excess capacity
97/// let mut excess = String::with_capacity(256);
98/// excess.push_str("abc");
99///
100/// let excess_c = CompactString::from(excess);
101/// assert!(!excess_c.is_heap_allocated());
102/// assert!(excess_c.capacity() < 256);
103///
104/// // re-using the same buffer
105/// let long = String::from("this is a longer string that will be heap allocated");
106///
107/// let long_ptr = long.as_ptr();
108/// let long_len = long.len();
109/// let long_cap = long.capacity();
110///
111/// let mut long_c = CompactString::from(long);
112/// assert!(long_c.is_heap_allocated());
113///
114/// let cpt_ptr = long_c.as_ptr();
115/// let cpt_len = long_c.len();
116/// let cpt_cap = long_c.capacity();
117///
118/// // the original String and the CompactString point to the same place in memory, buffer re-use!
119/// assert_eq!(cpt_ptr, long_ptr);
120/// assert_eq!(cpt_len, long_len);
121/// assert_eq!(cpt_cap, long_cap);
122/// ```
123///
124/// ### Prevent Eagerly Inlining
125/// A consequence of eagerly inlining is you then need to de-allocate the existing buffer, which
126/// might not always be desirable if you're converting a very large amount of `String`s. If your
127/// code is very sensitive to allocations, consider the [`CompactString::from_string_buffer`] API.
128#[repr(transparent)]
129pub struct CompactString(Repr);
130
131impl CompactString {
132 /// Creates a new [`CompactString`] from any type that implements `AsRef<str>`.
133 /// If the string is short enough, then it will be inlined on the stack! When `text` is an owned
134 /// [`String`] that does not fit inline, its existing allocation is reused.
135 ///
136 /// In a `static` or `const` context you can use the method [`CompactString::const_new()`].
137 ///
138 /// # Examples
139 ///
140 /// ### Inlined
141 /// ```
142 /// # use compact_str::CompactString;
143 /// // We can inline strings up to 12 characters long on 32-bit architectures...
144 /// #[cfg(target_pointer_width = "32")]
145 /// let s = "i'm 12 chars";
146 /// // ...and up to 24 characters on 64-bit architectures!
147 /// #[cfg(target_pointer_width = "64")]
148 /// let s = "i am 24 characters long!";
149 ///
150 /// let compact = CompactString::new(&s);
151 ///
152 /// assert_eq!(compact, s);
153 /// // we are not allocated on the heap!
154 /// assert!(!compact.is_heap_allocated());
155 /// ```
156 ///
157 /// ### Heap
158 /// ```
159 /// # use compact_str::CompactString;
160 /// // For longer strings though, we get allocated on the heap
161 /// let long = "I am a longer string that will be allocated on the heap";
162 /// let compact = CompactString::new(long);
163 ///
164 /// assert_eq!(compact, long);
165 /// // we are allocated on the heap!
166 /// assert!(compact.is_heap_allocated());
167 /// ```
168 ///
169 /// ### Creation
170 /// ```
171 /// use compact_str::CompactString;
172 ///
173 /// // Using a `&'static str`
174 /// let s = "hello world!";
175 /// let hello = CompactString::new(&s);
176 ///
177 /// // Using a `String`
178 /// let u = String::from("🦄🌈");
179 /// let unicorn = CompactString::new(u);
180 ///
181 /// // Using a `Box<str>`
182 /// let b: Box<str> = String::from("📦📦📦").into_boxed_str();
183 /// let boxed = CompactString::new(&b);
184 /// ```
185 #[inline]
186 #[track_caller]
187 pub fn new<T: AsRef<str>>(text: T) -> Self {
188 // Route `&str` through the infallible `new_panic` so the hot inline path avoids the
189 // `Result` machinery, while still reusing an owned `String`'s allocation via `from_string`.
190 let repr = match_type!(text, {
191 String as text => Repr::from_string(text, true).unwrap_with_msg(),
192 text => Repr::new_panic(text.as_ref()),
193 });
194
195 CompactString(repr)
196 }
197
198 /// Fallible version of [`CompactString::new()`]
199 ///
200 /// This method won't panic if the system is out-of-memory, but return an [`ReserveError`].
201 /// Otherwise it behaves the same as [`CompactString::new()`].
202 #[inline]
203 pub fn try_new<T: AsRef<str>>(text: T) -> Result<Self, ReserveError> {
204 let repr = match_type!(text, {
205 String as text => Repr::from_string(text, true)?,
206 text => Repr::new(text.as_ref())?,
207 });
208
209 Ok(CompactString(repr))
210 }
211
212 /// Creates a new inline [`CompactString`] from `&'static str` at compile time.
213 /// Complexity: O(1). As an optimization, short strings get inlined.
214 ///
215 /// In a dynamic context you can use the method [`CompactString::new()`].
216 ///
217 /// # Examples
218 /// ```
219 /// use compact_str::CompactString;
220 ///
221 /// const DEFAULT_NAME: CompactString = CompactString::const_new("untitled");
222 /// ```
223 #[inline]
224 pub const fn const_new(text: &'static str) -> Self {
225 CompactString(Repr::const_new(text))
226 }
227
228 /// Get back the `&'static str` constructed by [`CompactString::const_new`].
229 ///
230 /// If the string was short enough that it could be inlined, then it was inline, and
231 /// this method will return `None`.
232 ///
233 /// # Examples
234 /// ```
235 /// use compact_str::CompactString;
236 ///
237 /// const DEFAULT_NAME: CompactString =
238 /// CompactString::const_new("That is not dead which can eternal lie.");
239 /// assert_eq!(
240 /// DEFAULT_NAME.as_static_str().unwrap(),
241 /// "That is not dead which can eternal lie.",
242 /// );
243 /// ```
244 #[inline]
245 pub const fn as_static_str(&self) -> Option<&'static str> {
246 self.0.as_static_str()
247 }
248
249 /// Creates a new empty [`CompactString`] with the capacity to fit at least `capacity` bytes.
250 ///
251 /// A `CompactString` will inline strings on the stack, if they're small enough. Specifically,
252 /// if the string has a length less than or equal to `std::mem::size_of::<String>` bytes
253 /// then it will be inlined. This also means that `CompactString`s have a minimum capacity
254 /// of `std::mem::size_of::<String>`.
255 ///
256 /// # Panics
257 ///
258 /// This method panics if the system is out-of-memory.
259 /// Use [`CompactString::try_with_capacity()`] if you want to handle such a problem manually.
260 ///
261 /// # Examples
262 ///
263 /// ### "zero" Capacity
264 /// ```
265 /// # use compact_str::CompactString;
266 /// // Creating a CompactString with a capacity of 0 will create
267 /// // one with capacity of std::mem::size_of::<String>();
268 /// let empty = CompactString::with_capacity(0);
269 /// let min_size = std::mem::size_of::<String>();
270 ///
271 /// assert_eq!(empty.capacity(), min_size);
272 /// assert_ne!(0, min_size);
273 /// assert!(!empty.is_heap_allocated());
274 /// ```
275 ///
276 /// ### Max Inline Size
277 /// ```
278 /// # use compact_str::CompactString;
279 /// // Creating a CompactString with a capacity of std::mem::size_of::<String>()
280 /// // will not heap allocate.
281 /// let str_size = std::mem::size_of::<String>();
282 /// let empty = CompactString::with_capacity(str_size);
283 ///
284 /// assert_eq!(empty.capacity(), str_size);
285 /// assert!(!empty.is_heap_allocated());
286 /// ```
287 ///
288 /// ### Heap Allocating
289 /// ```
290 /// # use compact_str::CompactString;
291 /// // If you create a `CompactString` with a capacity greater than
292 /// // `std::mem::size_of::<String>`, it will heap allocated. For heap
293 /// // allocated strings we have a minimum capacity
294 ///
295 /// const MIN_HEAP_CAPACITY: usize = std::mem::size_of::<usize>() * 4;
296 ///
297 /// let heap_size = std::mem::size_of::<String>() + 1;
298 /// let empty = CompactString::with_capacity(heap_size);
299 ///
300 /// assert_eq!(empty.capacity(), MIN_HEAP_CAPACITY);
301 /// assert!(empty.is_heap_allocated());
302 /// ```
303 #[inline]
304 #[track_caller]
305 pub fn with_capacity(capacity: usize) -> Self {
306 Self::try_with_capacity(capacity).unwrap_with_msg()
307 }
308
309 /// Fallible version of [`CompactString::with_capacity()`]
310 ///
311 /// This method won't panic if the system is out-of-memory, but return an [`ReserveError`].
312 /// Otherwise it behaves the same as [`CompactString::with_capacity()`].
313 #[inline]
314 pub fn try_with_capacity(capacity: usize) -> Result<Self, ReserveError> {
315 Repr::with_capacity(capacity).map(CompactString)
316 }
317
318 /// Convert a slice of bytes into a [`CompactString`].
319 ///
320 /// A [`CompactString`] is a contiguous collection of bytes (`u8`s) that is valid [`UTF-8`](https://en.wikipedia.org/wiki/UTF-8).
321 /// This method converts from an arbitrary contiguous collection of bytes into a
322 /// [`CompactString`], failing if the provided bytes are not `UTF-8`.
323 ///
324 /// Note: If you want to create a [`CompactString`] from a non-contiguous collection of bytes,
325 /// enable the `bytes` feature of this crate, and see `CompactString::from_utf8_buf`
326 ///
327 /// # Examples
328 /// ### Valid UTF-8
329 /// ```
330 /// # use compact_str::CompactString;
331 /// let bytes = vec![240, 159, 166, 128, 240, 159, 146, 175];
332 /// let compact = CompactString::from_utf8(bytes).expect("valid UTF-8");
333 ///
334 /// assert_eq!(compact, "🦀💯");
335 /// ```
336 ///
337 /// ### Invalid UTF-8
338 /// ```
339 /// # use compact_str::CompactString;
340 /// let bytes = vec![255, 255, 255];
341 /// let result = CompactString::from_utf8(bytes);
342 ///
343 /// assert!(result.is_err());
344 /// ```
345 #[inline]
346 pub fn from_utf8<B: AsRef<[u8]>>(buf: B) -> Result<Self, Utf8Error> {
347 Repr::from_utf8(buf).map(CompactString)
348 }
349
350 /// Converts a vector of bytes to a [`CompactString`] without checking that the string contains
351 /// valid UTF-8.
352 ///
353 /// See the safe version, [`CompactString::from_utf8`], for more details.
354 ///
355 /// # Safety
356 ///
357 /// * The contents pased to this method must be valid UTF-8.
358 ///
359 /// It's very important that this constraint is upheld because the internals of a
360 /// [`CompactString`] (e.g. determing an inline string versus a heap allocated string) rely on
361 /// the [`CompactString`] containing valid UTF-8. If this constraint is violated any further
362 /// use of the returned [`CompactString`] (including dropping it) can cause undefined behavior.
363 ///
364 /// # Examples
365 ///
366 /// Basic usage:
367 ///
368 /// ```
369 /// # use compact_str::CompactString;
370 /// // some bytes, in a vector
371 /// let sparkle_heart = vec![240, 159, 146, 150];
372 ///
373 /// let sparkle_heart = unsafe {
374 /// CompactString::from_utf8_unchecked(sparkle_heart)
375 /// };
376 ///
377 /// assert_eq!("💖", sparkle_heart);
378 /// ```
379 #[inline]
380 #[must_use]
381 #[track_caller]
382 pub unsafe fn from_utf8_unchecked<B: AsRef<[u8]>>(buf: B) -> Self {
383 Repr::from_utf8_unchecked(buf)
384 .map(CompactString)
385 .unwrap_with_msg()
386 }
387
388 /// Decode a [`UTF-16`](https://en.wikipedia.org/wiki/UTF-16) slice of bytes into a
389 /// [`CompactString`], returning an [`Err`] if the slice contains any invalid data.
390 ///
391 /// # Examples
392 /// ### Valid UTF-16
393 /// ```
394 /// # use compact_str::CompactString;
395 /// let buf: &[u16] = &[0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0x0069, 0x0063];
396 /// let compact = CompactString::from_utf16(buf).unwrap();
397 ///
398 /// assert_eq!(compact, "𝄞music");
399 /// ```
400 ///
401 /// ### Invalid UTF-16
402 /// ```
403 /// # use compact_str::CompactString;
404 /// let buf: &[u16] = &[0xD834, 0xDD1E, 0x006d, 0x0075, 0xD800, 0x0069, 0x0063];
405 /// let res = CompactString::from_utf16(buf);
406 ///
407 /// assert!(res.is_err());
408 /// ```
409 #[inline]
410 pub fn from_utf16<B: AsRef<[u16]>>(buf: B) -> Result<Self, Utf16Error> {
411 // Note: we don't use collect::<Result<_, _>>() because that fails to pre-allocate a buffer,
412 // even though the size of our iterator, `buf`, is known ahead of time.
413 //
414 // rustlang issue #48994 is tracking the fix
415
416 let buf = buf.as_ref();
417 let mut ret = CompactString::with_capacity(buf.len());
418 for c in core::char::decode_utf16(buf.iter().copied()) {
419 if let Ok(c) = c {
420 ret.push(c);
421 } else {
422 return Err(Utf16Error(()));
423 }
424 }
425 Ok(ret)
426 }
427
428 /// Decode a UTF-16–encoded slice `v` into a `CompactString`, replacing invalid data with
429 /// the replacement character (`U+FFFD`), �.
430 ///
431 /// # Examples
432 ///
433 /// Basic usage:
434 ///
435 /// ```
436 /// # use compact_str::CompactString;
437 /// // 𝄞mus<invalid>ic<invalid>
438 /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075,
439 /// 0x0073, 0xDD1E, 0x0069, 0x0063,
440 /// 0xD834];
441 ///
442 /// assert_eq!(CompactString::from("𝄞mus\u{FFFD}ic\u{FFFD}"),
443 /// CompactString::from_utf16_lossy(v));
444 /// ```
445 #[inline]
446 pub fn from_utf16_lossy<B: AsRef<[u16]>>(buf: B) -> Self {
447 let buf = buf.as_ref();
448 let mut ret = CompactString::with_capacity(buf.len());
449 for c in core::char::decode_utf16(buf.iter().copied()) {
450 match c {
451 Ok(c) => ret.push(c),
452 Err(_) => ret.push_str("�"),
453 }
454 }
455 ret
456 }
457
458 /// Returns the length of the [`CompactString`] in `bytes`, not [`char`]s or graphemes.
459 ///
460 /// When using `UTF-8` encoding (which all strings in Rust do) a single character will be 1 to 4
461 /// bytes long, therefore the return value of this method might not be what a human considers
462 /// the length of the string.
463 ///
464 /// # Examples
465 /// ```
466 /// # use compact_str::CompactString;
467 /// let ascii = CompactString::new("hello world");
468 /// assert_eq!(ascii.len(), 11);
469 ///
470 /// let emoji = CompactString::new("👱");
471 /// assert_eq!(emoji.len(), 4);
472 /// ```
473 #[inline]
474 pub fn len(&self) -> usize {
475 self.0.len()
476 }
477
478 /// Returns `true` if the [`CompactString`] has a length of 0, `false` otherwise
479 ///
480 /// # Examples
481 /// ```
482 /// # use compact_str::CompactString;
483 /// let mut msg = CompactString::new("");
484 /// assert!(msg.is_empty());
485 ///
486 /// // add some characters
487 /// msg.push_str("hello reader!");
488 /// assert!(!msg.is_empty());
489 /// ```
490 #[inline]
491 pub fn is_empty(&self) -> bool {
492 self.0.is_empty()
493 }
494
495 /// Returns the capacity of the [`CompactString`], in bytes.
496 ///
497 /// # Note
498 /// * A `CompactString` will always have a capacity of at least `std::mem::size_of::<String>()`
499 ///
500 /// # Examples
501 /// ### Minimum Size
502 /// ```
503 /// # use compact_str::CompactString;
504 /// let min_size = std::mem::size_of::<String>();
505 /// let compact = CompactString::new("");
506 ///
507 /// assert!(compact.capacity() >= min_size);
508 /// ```
509 ///
510 /// ### Heap Allocated
511 /// ```
512 /// # use compact_str::CompactString;
513 /// let compact = CompactString::with_capacity(128);
514 /// assert_eq!(compact.capacity(), 128);
515 /// ```
516 #[inline]
517 pub fn capacity(&self) -> usize {
518 self.0.capacity()
519 }
520
521 /// Ensures that this [`CompactString`]'s capacity is at least `additional` bytes longer than
522 /// its length. The capacity may be increased by more than `additional` bytes if it chooses,
523 /// to prevent frequent reallocations.
524 ///
525 /// # Note
526 /// * A `CompactString` will always have at least a capacity of `std::mem::size_of::<String>()`
527 /// * Reserving additional bytes may cause the `CompactString` to become heap allocated
528 ///
529 /// # Panics
530 /// This method panics if the new capacity overflows `usize` or if the system is out-of-memory.
531 /// Use [`CompactString::try_reserve()`] if you want to handle such a problem manually.
532 ///
533 /// # Examples
534 /// ```
535 /// # use compact_str::CompactString;
536 ///
537 /// const WORD: usize = std::mem::size_of::<usize>();
538 /// let mut compact = CompactString::default();
539 /// assert!(compact.capacity() >= (WORD * 3) - 1);
540 ///
541 /// compact.reserve(200);
542 /// assert!(compact.is_heap_allocated());
543 /// assert!(compact.capacity() >= 200);
544 /// ```
545 #[inline]
546 #[track_caller]
547 pub fn reserve(&mut self, additional: usize) {
548 self.try_reserve(additional).unwrap_with_msg()
549 }
550
551 /// Fallible version of [`CompactString::reserve()`]
552 ///
553 /// This method won't panic if the system is out-of-memory, but return an [`ReserveError`]
554 /// Otherwise it behaves the same as [`CompactString::reserve()`].
555 #[inline]
556 pub fn try_reserve(&mut self, additional: usize) -> Result<(), ReserveError> {
557 self.0.reserve(additional)
558 }
559
560 /// Returns a string slice containing the entire [`CompactString`].
561 ///
562 /// # Examples
563 /// ```
564 /// # use compact_str::CompactString;
565 /// let s = CompactString::new("hello");
566 ///
567 /// assert_eq!(s.as_str(), "hello");
568 /// ```
569 #[inline]
570 pub fn as_str(&self) -> &str {
571 self.0.as_str()
572 }
573
574 /// Returns a mutable string slice containing the entire [`CompactString`].
575 ///
576 /// # Examples
577 /// ```
578 /// # use compact_str::CompactString;
579 /// let mut s = CompactString::new("hello");
580 /// s.as_mut_str().make_ascii_uppercase();
581 ///
582 /// assert_eq!(s.as_str(), "HELLO");
583 /// ```
584 #[inline]
585 pub fn as_mut_str(&mut self) -> &mut str {
586 let len = self.len();
587 let ptr = self.0.as_mut_ptr();
588 // SAFETY: The first `len` bytes of a `CompactString` are initialized and valid UTF-8.
589 let bytes = unsafe { slice::from_raw_parts_mut(ptr, len) };
590 // SAFETY: The bytes came from a valid `CompactString`.
591 unsafe { core::str::from_utf8_unchecked_mut(bytes) }
592 }
593
594 /// Returns the remaining spare capacity of this [`CompactString`] as a slice of
595 /// [`MaybeUninit`](mem::MaybeUninit) bytes.
596 ///
597 /// The returned slice covers the range `len()..capacity()`. After initializing a prefix of the
598 /// slice, use [`CompactString::set_len`] to include those bytes in the string.
599 ///
600 /// # Safety
601 ///
602 /// * Before increasing the length, the caller must initialize every newly included byte and
603 /// ensure the resulting string is valid UTF-8.
604 /// * For an inline string, the final byte of the spare capacity also stores the representation
605 /// tag. It may only be overwritten as the final byte of a completely initialized, valid
606 /// UTF-8 string that fills the inline capacity.
607 ///
608 /// # Examples
609 ///
610 /// ```
611 /// # use compact_str::CompactString;
612 /// let mut s = CompactString::new("hello");
613 /// let suffix = b" world";
614 ///
615 /// let spare = unsafe { s.spare_capacity_mut() };
616 /// for (slot, byte) in spare.iter_mut().zip(suffix) {
617 /// slot.write(*byte);
618 /// }
619 /// // SAFETY: We initialized the appended bytes, and the result is valid UTF-8.
620 /// unsafe { s.set_len(s.len() + suffix.len()) };
621 ///
622 /// assert_eq!(s, "hello world");
623 /// ```
624 #[inline]
625 pub unsafe fn spare_capacity_mut(&mut self) -> &mut [mem::MaybeUninit<u8>] {
626 let len = self.len();
627 let ptr = self.0.as_mut_ptr();
628 let cap = self.capacity();
629
630 // SAFETY: The buffer is valid for `cap` bytes, and `len <= cap`. `MaybeUninit<u8>` does
631 // not require the spare bytes to be initialized.
632 unsafe { slice::from_raw_parts_mut(ptr.add(len) as *mut mem::MaybeUninit<u8>, cap - len) }
633 }
634
635 /// Returns a byte slice of the [`CompactString`]'s contents.
636 ///
637 /// # Examples
638 /// ```
639 /// # use compact_str::CompactString;
640 /// let s = CompactString::new("hello");
641 ///
642 /// assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes());
643 /// ```
644 #[inline]
645 pub fn as_bytes(&self) -> &[u8] {
646 self.0.as_slice()
647 }
648
649 // TODO: Implement a `try_as_mut_slice(...)` that will fail if it results in cloning?
650 //
651 /// Provides a mutable reference to the initialized bytes in this [`CompactString`].
652 ///
653 /// The returned slice has length [`CompactString::len()`]. To write into the remaining
654 /// capacity, use [`CompactString::spare_capacity_mut`].
655 ///
656 /// # Safety
657 /// * All Rust strings, including `CompactString`, must be valid UTF-8. The caller must
658 /// guarantee that any modifications made to the underlying buffer are valid UTF-8.
659 ///
660 /// # Examples
661 /// ```
662 /// # use compact_str::CompactString;
663 /// let mut s = CompactString::new("hello");
664 ///
665 /// let bytes = unsafe { s.as_mut_bytes() };
666 /// bytes[0] = b'H';
667 ///
668 /// assert_eq!(s, "Hello");
669 /// ```
670 #[inline]
671 pub unsafe fn as_mut_bytes(&mut self) -> &mut [u8] {
672 let len = self.len();
673 let ptr = self.0.as_mut_ptr();
674
675 // SAFETY: The first `len` bytes of a `CompactString` are initialized.
676 unsafe { slice::from_raw_parts_mut(ptr, len) }
677 }
678
679 /// Appends the given [`char`] to the end of this [`CompactString`].
680 ///
681 /// # Examples
682 /// ```
683 /// # use compact_str::CompactString;
684 /// let mut s = CompactString::new("foo");
685 ///
686 /// s.push('b');
687 /// s.push('a');
688 /// s.push('r');
689 ///
690 /// assert_eq!("foobar", s);
691 /// ```
692 pub fn push(&mut self, ch: char) {
693 self.push_str(ch.encode_utf8(&mut [0; 4]));
694 }
695
696 /// Removes the last character from the [`CompactString`] and returns it.
697 /// Returns `None` if this [`CompactString`] is empty.
698 ///
699 /// # Examples
700 /// ```
701 /// # use compact_str::CompactString;
702 /// let mut s = CompactString::new("abc");
703 ///
704 /// assert_eq!(s.pop(), Some('c'));
705 /// assert_eq!(s.pop(), Some('b'));
706 /// assert_eq!(s.pop(), Some('a'));
707 ///
708 /// assert_eq!(s.pop(), None);
709 /// ```
710 #[inline]
711 pub fn pop(&mut self) -> Option<char> {
712 self.0.pop()
713 }
714
715 /// Appends a given string slice onto the end of this [`CompactString`]
716 ///
717 /// # Examples
718 /// ```
719 /// # use compact_str::CompactString;
720 /// let mut s = CompactString::new("abc");
721 ///
722 /// s.push_str("123");
723 ///
724 /// assert_eq!("abc123", s);
725 /// ```
726 #[inline]
727 pub fn push_str(&mut self, s: &str) {
728 self.0.push_str(s)
729 }
730
731 /// Removes a [`char`] from this [`CompactString`] at a byte position and returns it.
732 ///
733 /// This is an *O*(*n*) operation, as it requires copying every element in the
734 /// buffer.
735 ///
736 /// # Panics
737 ///
738 /// Panics if `idx` is larger than or equal to the [`CompactString`]'s length,
739 /// or if it does not lie on a [`char`] boundary.
740 ///
741 /// # Examples
742 ///
743 /// ### Basic usage:
744 ///
745 /// ```
746 /// # use compact_str::CompactString;
747 /// let mut c = CompactString::from("hello world");
748 ///
749 /// assert_eq!(c.remove(0), 'h');
750 /// assert_eq!(c, "ello world");
751 ///
752 /// assert_eq!(c.remove(5), 'w');
753 /// assert_eq!(c, "ello orld");
754 /// ```
755 ///
756 /// ### Past total length:
757 ///
758 /// ```should_panic
759 /// # use compact_str::CompactString;
760 /// let mut c = CompactString::from("hello there!");
761 /// c.remove(100);
762 /// ```
763 ///
764 /// ### Not on char boundary:
765 ///
766 /// ```should_panic
767 /// # use compact_str::CompactString;
768 /// let mut c = CompactString::from("🦄");
769 /// c.remove(1);
770 /// ```
771 #[inline]
772 pub fn remove(&mut self, idx: usize) -> char {
773 let len = self.len();
774 let substr = &mut self.as_mut_str()[idx..];
775
776 // get the char we want to remove
777 let ch = substr
778 .chars()
779 .next()
780 .expect("cannot remove a char from the end of a string");
781 let ch_len = ch.len_utf8();
782
783 // shift everything back one character
784 let num_bytes = substr.len() - ch_len;
785 let ptr = substr.as_mut_ptr();
786
787 // SAFETY: Both src and dest are valid for reads of `num_bytes` amount of bytes,
788 // and are properly aligned
789 unsafe {
790 core::ptr::copy(ptr.add(ch_len) as *const u8, ptr, num_bytes);
791 self.set_len(len - ch_len);
792 }
793
794 ch
795 }
796
797 /// Forces the length of the [`CompactString`] to `new_len`.
798 ///
799 /// This is a low-level operation that maintains none of the normal invariants for
800 /// `CompactString`. If you want to modify the `CompactString` you should use methods like
801 /// `push`, `push_str` or `pop`.
802 ///
803 /// # Safety
804 /// * `new_len` must be less than or equal to `capacity()`
805 /// * The elements at `old_len..new_len` must be initialized
806 #[inline]
807 pub unsafe fn set_len(&mut self, new_len: usize) {
808 self.0.set_len(new_len)
809 }
810
811 /// Returns whether or not the [`CompactString`] is heap allocated.
812 ///
813 /// # Examples
814 /// ### Inlined
815 /// ```
816 /// # use compact_str::CompactString;
817 /// let hello = CompactString::new("hello world");
818 ///
819 /// assert!(!hello.is_heap_allocated());
820 /// ```
821 ///
822 /// ### Heap Allocated
823 /// ```
824 /// # use compact_str::CompactString;
825 /// let msg = CompactString::new("this message will self destruct in 5, 4, 3, 2, 1 💥");
826 ///
827 /// assert!(msg.is_heap_allocated());
828 /// ```
829 #[inline]
830 pub fn is_heap_allocated(&self) -> bool {
831 self.0.is_heap_allocated()
832 }
833
834 /// Ensure that the given range is inside the set data, and that no codepoints are split.
835 ///
836 /// Returns the range `start..end` as a tuple.
837 #[inline]
838 fn ensure_range(&self, range: impl RangeBounds<usize>) -> (usize, usize) {
839 #[cold]
840 #[inline(never)]
841 fn illegal_range() -> ! {
842 panic!("illegal range");
843 }
844
845 let start = match range.start_bound() {
846 Bound::Included(&n) => n,
847 Bound::Excluded(&n) => match n.checked_add(1) {
848 Some(n) => n,
849 None => illegal_range(),
850 },
851 Bound::Unbounded => 0,
852 };
853 let end = match range.end_bound() {
854 Bound::Included(&n) => match n.checked_add(1) {
855 Some(n) => n,
856 None => illegal_range(),
857 },
858 Bound::Excluded(&n) => n,
859 Bound::Unbounded => self.len(),
860 };
861 if end < start {
862 illegal_range();
863 }
864
865 let s = self.as_str();
866 if !s.is_char_boundary(start) || !s.is_char_boundary(end) {
867 illegal_range();
868 }
869
870 (start, end)
871 }
872
873 /// Removes the specified range in the [`CompactString`],
874 /// and replaces it with the given string.
875 /// The given string doesn't need to be the same length as the range.
876 ///
877 /// # Panics
878 ///
879 /// Panics if the starting point or end point do not lie on a [`char`]
880 /// boundary, or if they're out of bounds.
881 ///
882 /// # Examples
883 ///
884 /// Basic usage:
885 ///
886 /// ```
887 /// # use compact_str::CompactString;
888 /// let mut s = CompactString::new("Hello, world!");
889 ///
890 /// s.replace_range(7..12, "WORLD");
891 /// assert_eq!(s, "Hello, WORLD!");
892 ///
893 /// s.replace_range(7..=11, "you");
894 /// assert_eq!(s, "Hello, you!");
895 ///
896 /// s.replace_range(5.., "! Is it me you're looking for?");
897 /// assert_eq!(s, "Hello! Is it me you're looking for?");
898 /// ```
899 #[inline]
900 pub fn replace_range(&mut self, range: impl RangeBounds<usize>, replace_with: &str) {
901 let (start, end) = self.ensure_range(range);
902 let dest_len = end - start;
903 match dest_len.cmp(&replace_with.len()) {
904 Ordering::Equal => unsafe { self.replace_range_same_size(start, end, replace_with) },
905 Ordering::Greater => unsafe { self.replace_range_shrink(start, end, replace_with) },
906 Ordering::Less => unsafe { self.replace_range_grow(start, end, replace_with) },
907 }
908 }
909
910 /// Replace into the same size.
911 unsafe fn replace_range_same_size(&mut self, start: usize, end: usize, replace_with: &str) {
912 core::ptr::copy_nonoverlapping(
913 replace_with.as_ptr(),
914 self.as_mut_ptr().add(start),
915 end - start,
916 );
917 }
918
919 /// Replace, so self.len() gets smaller.
920 unsafe fn replace_range_shrink(&mut self, start: usize, end: usize, replace_with: &str) {
921 let total_len = self.len();
922 let dest_len = end - start;
923 let new_len = total_len - (dest_len - replace_with.len());
924 let amount = total_len - end;
925 let data = self.as_mut_ptr();
926 // first insert the replacement string, overwriting the current content
927 core::ptr::copy_nonoverlapping(replace_with.as_ptr(), data.add(start), replace_with.len());
928 // then move the tail of the CompactString forward to its new place, filling the gap
929 core::ptr::copy(
930 data.add(total_len - amount),
931 data.add(new_len - amount),
932 amount,
933 );
934 // and lastly we set the new length
935 self.set_len(new_len);
936 }
937
938 /// Replace, so self.len() gets bigger.
939 unsafe fn replace_range_grow(&mut self, start: usize, end: usize, replace_with: &str) {
940 let dest_len = end - start;
941 self.reserve(replace_with.len() - dest_len);
942 let total_len = self.len();
943 let new_len = total_len + (replace_with.len() - dest_len);
944 let amount = total_len - end;
945 // first grow the string, so MIRI knows that the full range is usable
946 self.set_len(new_len);
947 let data = self.as_mut_ptr();
948 // then move the tail of the CompactString back to its new place
949 core::ptr::copy(
950 data.add(total_len - amount),
951 data.add(new_len - amount),
952 amount,
953 );
954 // and lastly insert the replacement string
955 core::ptr::copy_nonoverlapping(replace_with.as_ptr(), data.add(start), replace_with.len());
956 }
957
958 /// Creates a new [`CompactString`] by repeating a string `n` times.
959 ///
960 /// # Panics
961 ///
962 /// This function will panic if the capacity would overflow.
963 ///
964 /// # Examples
965 ///
966 /// Basic usage:
967 ///
968 /// ```
969 /// use compact_str::CompactString;
970 /// assert_eq!(CompactString::new("abc").repeat(4), CompactString::new("abcabcabcabc"));
971 /// ```
972 ///
973 /// A panic upon overflow:
974 ///
975 /// ```should_panic
976 /// use compact_str::CompactString;
977 ///
978 /// // this will panic at runtime
979 /// let huge = CompactString::new("0123456789abcdef").repeat(usize::MAX);
980 /// ```
981 #[must_use]
982 pub fn repeat(&self, n: usize) -> Self {
983 if n == 0 || self.is_empty() {
984 Self::const_new("")
985 } else if n == 1 {
986 self.clone()
987 } else {
988 let cap = self.len().checked_mul(n).expect("capacity overflow");
989 let mut out = Self::with_capacity(cap);
990 (0..n).for_each(|_| out.push_str(self));
991 out
992 }
993 }
994
995 /// Truncate the [`CompactString`] to a shorter length.
996 ///
997 /// If the length of the [`CompactString`] is less or equal to `new_len`, the call is a no-op.
998 ///
999 /// Calling this function does not change the capacity of the [`CompactString`], unless the
1000 /// [`CompactString`] is backed by a `&'static str`.
1001 ///
1002 /// # Panics
1003 ///
1004 /// Panics if the new end of the string does not lie on a [`char`] boundary.
1005 ///
1006 /// # Examples
1007 ///
1008 /// Basic usage:
1009 ///
1010 /// ```
1011 /// # use compact_str::CompactString;
1012 /// let mut s = CompactString::new("Hello, world!");
1013 /// s.truncate(5);
1014 /// assert_eq!(s, "Hello");
1015 /// ```
1016 pub fn truncate(&mut self, new_len: usize) {
1017 let s = self.as_str();
1018 if new_len >= s.len() {
1019 return;
1020 }
1021
1022 assert!(
1023 s.is_char_boundary(new_len),
1024 "new_len must lie on char boundary",
1025 );
1026 unsafe { self.set_len(new_len) };
1027 }
1028
1029 /// Converts a [`CompactString`] to a raw pointer.
1030 #[inline]
1031 pub fn as_ptr(&self) -> *const u8 {
1032 self.0.as_slice().as_ptr()
1033 }
1034
1035 /// Converts a mutable [`CompactString`] to a raw pointer.
1036 #[inline]
1037 pub fn as_mut_ptr(&mut self) -> *mut u8 {
1038 self.0.as_mut_ptr()
1039 }
1040
1041 /// Insert string character at an index.
1042 ///
1043 /// # Examples
1044 ///
1045 /// Basic usage:
1046 ///
1047 /// ```
1048 /// # use compact_str::CompactString;
1049 /// let mut s = CompactString::new("Hello!");
1050 /// s.insert_str(5, ", world");
1051 /// assert_eq!(s, "Hello, world!");
1052 /// ```
1053 pub fn insert_str(&mut self, idx: usize, string: &str) {
1054 assert!(self.is_char_boundary(idx), "idx must lie on char boundary");
1055
1056 let new_len = self.len() + string.len();
1057 self.reserve(string.len());
1058
1059 // SAFETY: We just checked that we may split self at idx.
1060 // We set the length only after reserving the memory.
1061 // We fill the gap with valid UTF-8 data.
1062 unsafe {
1063 // first move the tail to the new back
1064 let data = self.as_mut_ptr();
1065 core::ptr::copy(
1066 data.add(idx),
1067 data.add(idx + string.len()),
1068 new_len - idx - string.len(),
1069 );
1070
1071 // then insert the new bytes
1072 core::ptr::copy_nonoverlapping(string.as_ptr(), data.add(idx), string.len());
1073
1074 // and lastly resize the string
1075 self.set_len(new_len);
1076 }
1077 }
1078
1079 /// Insert a character at an index.
1080 ///
1081 /// # Examples
1082 ///
1083 /// Basic usage:
1084 ///
1085 /// ```
1086 /// # use compact_str::CompactString;
1087 /// let mut s = CompactString::new("Hello world!");
1088 /// s.insert(5, ',');
1089 /// assert_eq!(s, "Hello, world!");
1090 /// ```
1091 pub fn insert(&mut self, idx: usize, ch: char) {
1092 self.insert_str(idx, ch.encode_utf8(&mut [0; 4]));
1093 }
1094
1095 /// Reduces the length of the [`CompactString`] to zero.
1096 ///
1097 /// Calling this function does not change the capacity of the [`CompactString`], unless the
1098 /// [`CompactString`] is backed by a `&'static str`.
1099 ///
1100 /// ```
1101 /// # use compact_str::CompactString;
1102 /// let mut s = CompactString::new("Rust is the most loved language on Stackoverflow!");
1103 /// assert_eq!(s.capacity(), 49);
1104 ///
1105 /// s.clear();
1106 ///
1107 /// assert_eq!(s, "");
1108 /// assert_eq!(s.capacity(), 49);
1109 /// ```
1110 pub fn clear(&mut self) {
1111 unsafe { self.set_len(0) };
1112 }
1113
1114 /// Split the [`CompactString`] into at the given byte index.
1115 ///
1116 /// Calling this function does not change the capacity of the [`CompactString`], unless the
1117 /// [`CompactString`] is backed by a `&'static str`.
1118 ///
1119 /// # Panics
1120 ///
1121 /// Panics if `at` does not lie on a [`char`] boundary.
1122 ///
1123 /// Basic usage:
1124 ///
1125 /// ```
1126 /// # use compact_str::CompactString;
1127 /// let mut s = CompactString::const_new("Hello, world!");
1128 /// let w = s.split_off(5);
1129 ///
1130 /// assert_eq!(w, ", world!");
1131 /// assert_eq!(s, "Hello");
1132 /// ```
1133 pub fn split_off(&mut self, at: usize) -> Self {
1134 if let Some(s) = self.as_static_str() {
1135 let result = Self::const_new(&s[at..]);
1136 // SAFETY: the previous line `self[at...]` would have panicked if `at` was invalid
1137 unsafe { self.set_len(at) };
1138 result
1139 } else {
1140 let result = self[at..].into();
1141 // SAFETY: the previous line `self[at...]` would have panicked if `at` was invalid
1142 unsafe { self.set_len(at) };
1143 result
1144 }
1145 }
1146
1147 /// Remove a range from the [`CompactString`], and return it as an iterator.
1148 ///
1149 /// Calling this function does not change the capacity of the [`CompactString`].
1150 ///
1151 /// # Panics
1152 ///
1153 /// Panics if the start or end of the range does not lie on a [`char`] boundary.
1154 ///
1155 /// # Examples
1156 ///
1157 /// Basic usage:
1158 ///
1159 /// ```
1160 /// # use compact_str::CompactString;
1161 /// let mut s = CompactString::new("Hello, world!");
1162 ///
1163 /// let mut d = s.drain(5..12);
1164 /// assert_eq!(d.next(), Some(',')); // iterate over the extracted data
1165 /// assert_eq!(d.as_str(), " world"); // or get the whole data as &str
1166 ///
1167 /// // The iterator keeps a reference to `s`, so you have to drop() the iterator,
1168 /// // before you can access `s` again.
1169 /// drop(d);
1170 /// assert_eq!(s, "Hello!");
1171 /// ```
1172 pub fn drain(&mut self, range: impl RangeBounds<usize>) -> Drain<'_> {
1173 let (start, end) = self.ensure_range(range);
1174 Drain {
1175 compact_string: self as *mut Self,
1176 start,
1177 end,
1178 chars: self[start..end].chars(),
1179 }
1180 }
1181
1182 /// Shrinks the capacity of this [`CompactString`] with a lower bound.
1183 ///
1184 /// The resulting capactity is never less than the size of 3×[`usize`],
1185 /// i.e. the capacity than can be inlined.
1186 ///
1187 /// # Examples
1188 ///
1189 /// Basic usage:
1190 ///
1191 /// ```
1192 /// # use compact_str::CompactString;
1193 /// let mut s = CompactString::with_capacity(100);
1194 /// assert_eq!(s.capacity(), 100);
1195 ///
1196 /// // if the capacity was already bigger than the argument, the call is a no-op
1197 /// s.shrink_to(100);
1198 /// assert_eq!(s.capacity(), 100);
1199 ///
1200 /// s.shrink_to(50);
1201 /// assert_eq!(s.capacity(), 50);
1202 ///
1203 /// // if the string can be inlined, it is
1204 /// s.shrink_to(10);
1205 /// assert_eq!(s.capacity(), 3 * std::mem::size_of::<usize>());
1206 /// ```
1207 #[inline]
1208 pub fn shrink_to(&mut self, min_capacity: usize) {
1209 self.0.shrink_to(min_capacity);
1210 }
1211
1212 /// Shrinks the capacity of this [`CompactString`] to match its length.
1213 ///
1214 /// The resulting capactity is never less than the size of 3×[`usize`],
1215 /// i.e. the capacity than can be inlined.
1216 ///
1217 /// This method is effectively the same as calling `string.shrink_to(0)`.
1218 ///
1219 /// # Examples
1220 ///
1221 /// Basic usage:
1222 ///
1223 /// ```
1224 /// # use compact_str::CompactString;
1225 /// let mut s = CompactString::from("This is a string with more than 24 characters.");
1226 ///
1227 /// s.reserve(100);
1228 /// assert!(s.capacity() >= 100);
1229 ///
1230 /// s.shrink_to_fit();
1231 /// assert_eq!(s.len(), s.capacity());
1232 /// ```
1233 ///
1234 /// ```
1235 /// # use compact_str::CompactString;
1236 /// let mut s = CompactString::from("short string");
1237 ///
1238 /// s.reserve(100);
1239 /// assert!(s.capacity() >= 100);
1240 ///
1241 /// s.shrink_to_fit();
1242 /// assert_eq!(s.capacity(), 3 * std::mem::size_of::<usize>());
1243 /// ```
1244 #[inline]
1245 pub fn shrink_to_fit(&mut self) {
1246 self.0.shrink_to(0);
1247 }
1248
1249 /// Retains only the characters specified by the predicate.
1250 ///
1251 /// The method iterates over the characters in the string and calls the `predicate`.
1252 ///
1253 /// If the `predicate` returns `false`, then the character gets removed.
1254 /// If the `predicate` returns `true`, then the character is kept.
1255 ///
1256 /// # Examples
1257 ///
1258 /// ```
1259 /// # use compact_str::CompactString;
1260 /// let mut s = CompactString::from("äb𝄞d€");
1261 ///
1262 /// let keep = [false, true, true, false, true];
1263 /// let mut iter = keep.iter();
1264 /// s.retain(|_| *iter.next().unwrap());
1265 ///
1266 /// assert_eq!(s, "b𝄞€");
1267 /// ```
1268 pub fn retain(&mut self, mut predicate: impl FnMut(char) -> bool) {
1269 // We iterate over the string, and copy character by character.
1270
1271 struct SetLenOnDrop<'a> {
1272 self_: &'a mut CompactString,
1273 src_idx: usize,
1274 dst_idx: usize,
1275 }
1276
1277 let mut g = SetLenOnDrop {
1278 self_: self,
1279 src_idx: 0,
1280 dst_idx: 0,
1281 };
1282 let original_len = g.self_.len();
1283 let ptr = g.self_.0.as_mut_ptr();
1284 while g.src_idx < original_len {
1285 // SAFETY: Everything at and after `src_idx` is an untouched suffix of the
1286 // original string. In particular, it is initialized, valid UTF-8, and non-empty.
1287 let ch = unsafe {
1288 let suffix =
1289 core::slice::from_raw_parts(ptr.add(g.src_idx), original_len - g.src_idx);
1290 core::str::from_utf8_unchecked(suffix)
1291 .chars()
1292 .next()
1293 .expect("source suffix is non-empty")
1294 };
1295 let ch_len = ch.len_utf8();
1296 if predicate(ch) {
1297 // SAFETY: Both ranges are in the allocation and `copy` permits overlap. The
1298 // destination ends no later than the end of the current source character, so
1299 // the unprocessed suffix remains unchanged.
1300 unsafe {
1301 core::ptr::copy(ptr.add(g.src_idx), ptr.add(g.dst_idx), ch_len);
1302 }
1303 g.dst_idx += ch_len;
1304 }
1305 g.src_idx += ch_len;
1306 }
1307
1308 impl Drop for SetLenOnDrop<'_> {
1309 fn drop(&mut self) {
1310 // SAFETY: We know that the index is a valid position to break the string.
1311 unsafe { self.self_.set_len(self.dst_idx) };
1312 }
1313 }
1314 drop(g);
1315 }
1316
1317 /// Decode a bytes slice as UTF-8 string, replacing any illegal codepoints
1318 ///
1319 /// # Examples
1320 ///
1321 /// ```
1322 /// # use compact_str::CompactString;
1323 /// let chess_knight = b"\xf0\x9f\xa8\x84";
1324 ///
1325 /// assert_eq!(
1326 /// "🨄",
1327 /// CompactString::from_utf8_lossy(chess_knight),
1328 /// );
1329 ///
1330 /// // For valid UTF-8 slices, this is the same as:
1331 /// assert_eq!(
1332 /// "🨄",
1333 /// CompactString::new(std::str::from_utf8(chess_knight).unwrap()),
1334 /// );
1335 /// ```
1336 ///
1337 /// Incorrect bytes:
1338 ///
1339 /// ```
1340 /// # use compact_str::CompactString;
1341 /// let broken = b"\xf0\x9f\xc8\x84";
1342 ///
1343 /// assert_eq!(
1344 /// "�Ȅ",
1345 /// CompactString::from_utf8_lossy(broken),
1346 /// );
1347 ///
1348 /// // For invalid UTF-8 slices, this is an optimized implemented for:
1349 /// assert_eq!(
1350 /// "�Ȅ",
1351 /// CompactString::from(String::from_utf8_lossy(broken)),
1352 /// );
1353 /// ```
1354 pub fn from_utf8_lossy(v: &[u8]) -> Self {
1355 // Fast path: the entire input is valid UTF-8, so copy it in a single shot. This is the
1356 // common case, and mirrors `String::from_utf8_lossy`, which borrows the input here.
1357 let mut error = match core::str::from_utf8(v) {
1358 Ok(valid) => return Self::new(valid),
1359 Err(error) => error,
1360 };
1361
1362 // Slow path: bulk-copy each run of valid UTF-8, emitting a single replacement character for
1363 // every maximal invalid subsequence. This produces the same result as
1364 // `String::from_utf8_lossy`, but writes straight into the `CompactString` rather than
1365 // building an intermediate `String`.
1366 const REPLACEMENT: &str = "\u{FFFD}";
1367 // `v.len()` is a heuristic, not an upper bound: a 1-byte invalid subsequence expands to the
1368 // 3-byte replacement character, so pathological all-invalid input may reallocate. This
1369 // matches what `String::from_utf8_lossy` does (`String::with_capacity(v.len())`).
1370 let mut result = Self::with_capacity(v.len());
1371 let mut remaining = v;
1372 loop {
1373 let valid_up_to = error.valid_up_to();
1374 // SAFETY: `remaining[..valid_up_to]` is valid UTF-8, by definition of `valid_up_to`.
1375 let valid = unsafe { core::str::from_utf8_unchecked(&remaining[..valid_up_to]) };
1376 result.push_str(valid);
1377 result.push_str(REPLACEMENT);
1378
1379 let invalid_len = match error.error_len() {
1380 Some(len) => len,
1381 // `None` means the input ended with an incomplete (but not yet invalid) sequence,
1382 // which we've now replaced, so we're done.
1383 None => return result,
1384 };
1385 remaining = &remaining[valid_up_to + invalid_len..];
1386
1387 // Re-validate the rest. If it's all valid we're done; otherwise loop on the next error.
1388 match core::str::from_utf8(remaining) {
1389 Ok(valid) => {
1390 result.push_str(valid);
1391 return result;
1392 }
1393 Err(next) => error = next,
1394 }
1395 }
1396 }
1397
1398 fn from_utf16x(
1399 v: &[u8],
1400 from_int: impl Fn(u16) -> u16,
1401 from_bytes: impl Fn([u8; 2]) -> u16,
1402 ) -> Result<Self, Utf16Error> {
1403 #[allow(clippy::manual_is_multiple_of)]
1404 if v.len() % 2 != 0 {
1405 // Input had an odd number of bytes.
1406 return Err(Utf16Error(()));
1407 }
1408
1409 // Note: we don't use collect::<Result<_, _>>() because that fails to pre-allocate a buffer,
1410 // even though the size of our iterator, `v`, is known ahead of time.
1411 //
1412 // rustlang issue #48994 is tracking the fix
1413 let mut result = CompactString::with_capacity(v.len() / 2);
1414
1415 // SAFETY: `u8` and `u16` are `Copy`, so if the alignment fits, we can transmute a
1416 // `[u8; 2*N]` to `[u16; N]`. `slice::align_to()` checks if the alignment is right.
1417 match unsafe { v.align_to::<u16>() } {
1418 (&[], v, &[]) => {
1419 // Input is correctly aligned.
1420 for c in core::char::decode_utf16(v.iter().copied().map(from_int)) {
1421 result.push(c.map_err(|_| Utf16Error(()))?);
1422 }
1423 }
1424 _ => {
1425 // Input's alignment is off.
1426 // SAFETY: we can always reinterpret a `[u8; 2*N]` slice as `[[u8; 2]; N]`
1427 let v = unsafe { slice::from_raw_parts(v.as_ptr().cast(), v.len() / 2) };
1428 for c in core::char::decode_utf16(v.iter().copied().map(from_bytes)) {
1429 result.push(c.map_err(|_| Utf16Error(()))?);
1430 }
1431 }
1432 }
1433
1434 Ok(result)
1435 }
1436
1437 fn from_utf16x_lossy(
1438 v: &[u8],
1439 from_int: impl Fn(u16) -> u16,
1440 from_bytes: impl Fn([u8; 2]) -> u16,
1441 ) -> Self {
1442 // Notice: We write the string "�" instead of the character '�', so the character does not
1443 // have to be formatted before it can be appended.
1444
1445 #[allow(clippy::manual_is_multiple_of)]
1446 let (trailing_extra_byte, v) = match v.len() % 2 != 0 {
1447 true => (true, &v[..v.len() - 1]),
1448 false => (false, v),
1449 };
1450 let mut result = CompactString::with_capacity(v.len() / 2);
1451
1452 // SAFETY: `u8` and `u16` are `Copy`, so if the alignment fits, we can transmute a
1453 // `[u8; 2*N]` to `[u16; N]`. `slice::align_to()` checks if the alignment is right.
1454 match unsafe { v.align_to::<u16>() } {
1455 (&[], v, &[]) => {
1456 // Input is correctly aligned.
1457 for c in core::char::decode_utf16(v.iter().copied().map(from_int)) {
1458 match c {
1459 Ok(c) => result.push(c),
1460 Err(_) => result.push_str("�"),
1461 }
1462 }
1463 }
1464 _ => {
1465 // Input's alignment is off.
1466 // SAFETY: we can always reinterpret a `[u8; 2*N]` slice as `[[u8; 2]; N]`
1467 let v = unsafe { slice::from_raw_parts(v.as_ptr().cast(), v.len() / 2) };
1468 for c in core::char::decode_utf16(v.iter().copied().map(from_bytes)) {
1469 match c {
1470 Ok(c) => result.push(c),
1471 Err(_) => result.push_str("�"),
1472 }
1473 }
1474 }
1475 }
1476
1477 if trailing_extra_byte {
1478 result.push_str("�");
1479 }
1480 result
1481 }
1482
1483 /// Decode a slice of bytes as UTF-16 encoded string, in little endian.
1484 ///
1485 /// # Errors
1486 ///
1487 /// If the slice has an odd number of bytes, or if it did not contain valid UTF-16 characters,
1488 /// a [`Utf16Error`] is returned.
1489 ///
1490 /// # Examples
1491 ///
1492 /// ```
1493 /// # use compact_str::CompactString;
1494 /// const DANCING_MEN: &[u8] = b"\x3d\xd8\x6f\xdc\x0d\x20\x42\x26\x0f\xfe";
1495 /// let dancing_men = CompactString::from_utf16le(DANCING_MEN).unwrap();
1496 /// assert_eq!(dancing_men, "👯♂️");
1497 /// ```
1498 #[inline]
1499 pub fn from_utf16le(v: impl AsRef<[u8]>) -> Result<Self, Utf16Error> {
1500 CompactString::from_utf16x(v.as_ref(), u16::from_le, u16::from_le_bytes)
1501 }
1502
1503 /// Decode a slice of bytes as UTF-16 encoded string, in big endian.
1504 ///
1505 /// # Errors
1506 ///
1507 /// If the slice has an odd number of bytes, or if it did not contain valid UTF-16 characters,
1508 /// a [`Utf16Error`] is returned.
1509 ///
1510 /// # Examples
1511 ///
1512 /// ```
1513 /// # use compact_str::CompactString;
1514 /// const DANCING_WOMEN: &[u8] = b"\xd8\x3d\xdc\x6f\x20\x0d\x26\x40\xfe\x0f";
1515 /// let dancing_women = CompactString::from_utf16be(DANCING_WOMEN).unwrap();
1516 /// assert_eq!(dancing_women, "👯♀️");
1517 /// ```
1518 #[inline]
1519 pub fn from_utf16be(v: impl AsRef<[u8]>) -> Result<Self, Utf16Error> {
1520 CompactString::from_utf16x(v.as_ref(), u16::from_be, u16::from_be_bytes)
1521 }
1522
1523 /// Lossy decode a slice of bytes as UTF-16 encoded string, in little endian.
1524 ///
1525 /// In this context "lossy" means that any broken characters in the input are replaced by the
1526 /// \<REPLACEMENT CHARACTER\> `'�'`. Please notice that, unlike UTF-8, UTF-16 is not self
1527 /// synchronizing. I.e. if a byte in the input is dropped, all following data is broken.
1528 ///
1529 /// # Examples
1530 ///
1531 /// ```
1532 /// # use compact_str::CompactString;
1533 /// // A "random" bit was flipped in the 4th byte:
1534 /// const DANCING_MEN: &[u8] = b"\x3d\xd8\x6f\xfc\x0d\x20\x42\x26\x0f\xfe";
1535 /// let dancing_men = CompactString::from_utf16le_lossy(DANCING_MEN);
1536 /// assert_eq!(dancing_men, "�\u{fc6f}\u{200d}♂️");
1537 /// ```
1538 #[inline]
1539 pub fn from_utf16le_lossy(v: impl AsRef<[u8]>) -> Self {
1540 CompactString::from_utf16x_lossy(v.as_ref(), u16::from_le, u16::from_le_bytes)
1541 }
1542
1543 /// Lossy decode a slice of bytes as UTF-16 encoded string, in big endian.
1544 ///
1545 /// In this context "lossy" means that any broken characters in the input are replaced by the
1546 /// \<REPLACEMENT CHARACTER\> `'�'`. Please notice that, unlike UTF-8, UTF-16 is not self
1547 /// synchronizing. I.e. if a byte in the input is dropped, all following data is broken.
1548 ///
1549 /// # Examples
1550 ///
1551 /// ```
1552 /// # use compact_str::CompactString;
1553 /// // A "random" bit was flipped in the 9th byte:
1554 /// const DANCING_WOMEN: &[u8] = b"\xd8\x3d\xdc\x6f\x20\x0d\x26\x40\xde\x0f";
1555 /// let dancing_women = CompactString::from_utf16be_lossy(DANCING_WOMEN);
1556 /// assert_eq!(dancing_women, "👯\u{200d}♀�");
1557 /// ```
1558 #[inline]
1559 pub fn from_utf16be_lossy(v: impl AsRef<[u8]>) -> Self {
1560 CompactString::from_utf16x_lossy(v.as_ref(), u16::from_be, u16::from_be_bytes)
1561 }
1562
1563 /// Convert the [`CompactString`] into a [`String`].
1564 ///
1565 /// # Examples
1566 ///
1567 /// ```
1568 /// # use compact_str::CompactString;
1569 /// let s = CompactString::new("Hello world");
1570 /// let s = s.into_string();
1571 /// assert_eq!(s, "Hello world");
1572 /// ```
1573 pub fn into_string(self) -> String {
1574 self.0.into_string()
1575 }
1576
1577 /// Convert a [`String`] into a [`CompactString`] _without inlining_.
1578 ///
1579 /// Note: You probably don't need to use this method, instead you should use `From<String>`
1580 /// which is implemented for [`CompactString`].
1581 ///
1582 /// This method exists incase your code is very sensitive to memory allocations. Normally when
1583 /// converting a [`String`] to a [`CompactString`] we'll inline short strings onto the stack.
1584 /// But this results in [`Drop`]-ing the original [`String`], which causes memory it owned on
1585 /// the heap to be deallocated. Instead when using this method, we always reuse the buffer that
1586 /// was previously owned by the [`String`], so no trips to the allocator are needed.
1587 ///
1588 /// # Examples
1589 ///
1590 /// ### Short Strings
1591 /// ```
1592 /// use compact_str::CompactString;
1593 ///
1594 /// let short = "hello world".to_string();
1595 /// let c_heap = CompactString::from_string_buffer(short);
1596 ///
1597 /// // using CompactString::from_string_buffer, we'll re-use the String's underlying buffer
1598 /// assert!(c_heap.is_heap_allocated());
1599 ///
1600 /// // note: when Clone-ing a short heap allocated string, we'll eagerly inline at that point
1601 /// let c_inline = c_heap.clone();
1602 /// assert!(!c_inline.is_heap_allocated());
1603 ///
1604 /// assert_eq!(c_heap, c_inline);
1605 /// ```
1606 ///
1607 /// ### Longer Strings
1608 /// ```
1609 /// use compact_str::CompactString;
1610 ///
1611 /// let x = "longer string that will be on the heap".to_string();
1612 /// let c1 = CompactString::from(x);
1613 ///
1614 /// let y = "longer string that will be on the heap".to_string();
1615 /// let c2 = CompactString::from_string_buffer(y);
1616 ///
1617 /// // for longer strings, we re-use the underlying String's buffer in both cases
1618 /// assert!(c1.is_heap_allocated());
1619 /// assert!(c2.is_heap_allocated());
1620 /// ```
1621 ///
1622 /// ### Buffer Re-use
1623 /// ```
1624 /// use compact_str::CompactString;
1625 ///
1626 /// let og = "hello world".to_string();
1627 /// let og_addr = og.as_ptr();
1628 ///
1629 /// let mut c = CompactString::from_string_buffer(og);
1630 /// let ex_addr = c.as_ptr();
1631 ///
1632 /// // When converting to/from String and CompactString with from_string_buffer we always re-use
1633 /// // the same underlying allocated memory/buffer
1634 /// assert_eq!(og_addr, ex_addr);
1635 ///
1636 /// let long = "this is a long string that will be on the heap".to_string();
1637 /// let long_addr = long.as_ptr();
1638 ///
1639 /// let mut long_c = CompactString::from(long);
1640 /// let long_ex_addr = long_c.as_ptr();
1641 ///
1642 /// // When converting to/from String and CompactString with From<String>, we'll also re-use the
1643 /// // underlying buffer, if the string is long, otherwise when converting to CompactString we
1644 /// // eagerly inline
1645 /// assert_eq!(long_addr, long_ex_addr);
1646 /// ```
1647 #[inline]
1648 #[track_caller]
1649 pub fn from_string_buffer(s: String) -> Self {
1650 let repr = Repr::from_string(s, false).unwrap_with_msg();
1651 CompactString(repr)
1652 }
1653
1654 /// Returns a copy of this string where each character is mapped to its
1655 /// ASCII lower case equivalent.
1656 ///
1657 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
1658 /// but non-ASCII letters are unchanged.
1659 ///
1660 /// To lowercase the value in-place, use [`str::make_ascii_lowercase`].
1661 ///
1662 /// To lowercase ASCII characters in addition to non-ASCII characters, use
1663 /// [`CompactString::to_lowercase`].
1664 ///
1665 /// # Examples
1666 ///
1667 /// ```
1668 /// use compact_str::CompactString;
1669 /// let s = CompactString::new("Grüße, Jürgen ❤");
1670 ///
1671 /// assert_eq!("grüße, jürgen ❤", s.to_ascii_lowercase());
1672 /// ```
1673 #[must_use = "to lowercase the value in-place, use `make_ascii_lowercase()`"]
1674 #[inline]
1675 pub fn to_ascii_lowercase(&self) -> Self {
1676 let mut s = self.clone();
1677 s.make_ascii_lowercase();
1678 s
1679 }
1680
1681 /// Returns a copy of this string where each character is mapped to its
1682 /// ASCII upper case equivalent.
1683 ///
1684 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
1685 /// but non-ASCII letters are unchanged.
1686 ///
1687 /// To uppercase the value in-place, use [`str::make_ascii_uppercase`].
1688 ///
1689 /// To uppercase ASCII characters in addition to non-ASCII characters, use
1690 /// [`CompactString::to_uppercase`].
1691 ///
1692 /// # Examples
1693 ///
1694 /// ```
1695 /// use compact_str::CompactString;
1696 /// let s = CompactString::new("Grüße, Jürgen ❤");
1697 ///
1698 /// assert_eq!("GRüßE, JüRGEN ❤", s.to_ascii_uppercase());
1699 /// ```
1700 #[must_use = "to uppercase the value in-place, use `make_ascii_uppercase()`"]
1701 #[inline]
1702 pub fn to_ascii_uppercase(&self) -> Self {
1703 let mut s = self.clone();
1704 s.make_ascii_uppercase();
1705 s
1706 }
1707
1708 /// Returns the lowercase equivalent of this string slice, as a new [`CompactString`].
1709 ///
1710 /// 'Lowercase' is defined according to the terms of the Unicode Derived Core Property
1711 /// `Lowercase`.
1712 ///
1713 /// Since some characters can expand into multiple characters when changing
1714 /// the case, this function returns a [`CompactString`] instead of modifying the
1715 /// parameter in-place.
1716 ///
1717 /// # Examples
1718 ///
1719 /// Basic usage:
1720 ///
1721 /// ```
1722 /// use compact_str::CompactString;
1723 /// let s = CompactString::new("HELLO");
1724 ///
1725 /// assert_eq!("hello", s.to_lowercase());
1726 /// ```
1727 ///
1728 /// A tricky example, with sigma:
1729 ///
1730 /// ```
1731 /// use compact_str::CompactString;
1732 /// let sigma = CompactString::new("Σ");
1733 ///
1734 /// assert_eq!("σ", sigma.to_lowercase());
1735 ///
1736 /// // but at the end of a word, it's ς, not σ:
1737 /// let odysseus = CompactString::new("ὈΔΥΣΣΕΎΣ");
1738 ///
1739 /// assert_eq!("ὀδυσσεύς", odysseus.to_lowercase());
1740 /// ```
1741 ///
1742 /// Languages without case are not changed:
1743 ///
1744 /// ```
1745 /// use compact_str::CompactString;
1746 /// let new_year = CompactString::new("农历新年");
1747 ///
1748 /// assert_eq!(new_year, new_year.to_lowercase());
1749 /// ```
1750 #[must_use = "this returns the lowercase string as a new CompactString, \
1751 without modifying the original"]
1752 pub fn to_lowercase(&self) -> Self {
1753 Self::from_str_to_lowercase(self.as_str())
1754 }
1755
1756 /// Returns the lowercase equivalent of this string slice, as a new [`CompactString`].
1757 ///
1758 /// 'Lowercase' is defined according to the terms of the Unicode Derived Core Property
1759 /// `Lowercase`.
1760 ///
1761 /// Since some characters can expand into multiple characters when changing
1762 /// the case, this function returns a [`CompactString`] instead of modifying the
1763 /// parameter in-place.
1764 ///
1765 /// # Examples
1766 ///
1767 /// Basic usage:
1768 ///
1769 /// ```
1770 /// use compact_str::CompactString;
1771 ///
1772 /// assert_eq!("hello", CompactString::from_str_to_lowercase("HELLO"));
1773 /// ```
1774 ///
1775 /// A tricky example, with sigma:
1776 ///
1777 /// ```
1778 /// use compact_str::CompactString;
1779 ///
1780 /// assert_eq!("σ", CompactString::from_str_to_lowercase("Σ"));
1781 ///
1782 /// // but at the end of a word, it's ς, not σ:
1783 /// assert_eq!("ὀδυσσεύς", CompactString::from_str_to_lowercase("ὈΔΥΣΣΕΎΣ"));
1784 /// ```
1785 ///
1786 /// Languages without case are not changed:
1787 ///
1788 /// ```
1789 /// use compact_str::CompactString;
1790 ///
1791 /// let new_year = "农历新年";
1792 /// assert_eq!(new_year, CompactString::from_str_to_lowercase(new_year));
1793 /// ```
1794 #[must_use = "this returns the lowercase string as a new CompactString, \
1795 without modifying the original"]
1796 pub fn from_str_to_lowercase(input: &str) -> Self {
1797 let mut s = convert_while_ascii(input.as_bytes(), u8::to_ascii_lowercase);
1798
1799 // Safety: we know this is a valid char boundary since
1800 // out.len() is only progressed if ascii bytes are found
1801 let rest = unsafe { input.get_unchecked(s.len()..) };
1802
1803 for (i, c) in rest.char_indices() {
1804 if c == 'Σ' {
1805 // Σ maps to σ, except at the end of a word where it maps to ς.
1806 // This is the only conditional (contextual) but language-independent mapping
1807 // in `SpecialCasing.txt`,
1808 // so hard-code it rather than have a generic "condition" mechanism.
1809 // See https://github.com/rust-lang/rust/issues/26035
1810 map_uppercase_sigma(rest, i, &mut s)
1811 } else {
1812 s.extend(c.to_lowercase());
1813 }
1814 }
1815 return s;
1816
1817 fn map_uppercase_sigma(from: &str, i: usize, to: &mut CompactString) {
1818 // See https://www.unicode.org/versions/Unicode7.0.0/ch03.pdf#G33992
1819 // for the definition of `Final_Sigma`.
1820 debug_assert!('Σ'.len_utf8() == 2);
1821 let is_word_final = case_ignorable_then_cased(from[..i].chars().rev())
1822 && !case_ignorable_then_cased(from[i + 2..].chars());
1823 to.push_str(if is_word_final { "ς" } else { "σ" });
1824 }
1825
1826 fn case_ignorable_then_cased<I: Iterator<Item = char>>(mut iter: I) -> bool {
1827 use unicode_data::case_ignorable::lookup as Case_Ignorable;
1828 use unicode_data::cased::lookup as Cased;
1829 match iter.find(|&c| !Case_Ignorable(c)) {
1830 Some(c) => Cased(c),
1831 None => false,
1832 }
1833 }
1834 }
1835
1836 /// Returns the uppercase equivalent of this string slice, as a new [`CompactString`].
1837 ///
1838 /// 'Uppercase' is defined according to the terms of the Unicode Derived Core Property
1839 /// `Uppercase`.
1840 ///
1841 /// Since some characters can expand into multiple characters when changing
1842 /// the case, this function returns a [`CompactString`] instead of modifying the
1843 /// parameter in-place.
1844 ///
1845 /// # Examples
1846 ///
1847 /// Basic usage:
1848 ///
1849 /// ```
1850 /// use compact_str::CompactString;
1851 /// let s = CompactString::new("hello");
1852 ///
1853 /// assert_eq!("HELLO", s.to_uppercase());
1854 /// ```
1855 ///
1856 /// Scripts without case are not changed:
1857 ///
1858 /// ```
1859 /// use compact_str::CompactString;
1860 /// let new_year = CompactString::new("农历新年");
1861 ///
1862 /// assert_eq!(new_year, new_year.to_uppercase());
1863 /// ```
1864 ///
1865 /// One character can become multiple:
1866 /// ```
1867 /// use compact_str::CompactString;
1868 /// let s = CompactString::new("tschüß");
1869 ///
1870 /// assert_eq!("TSCHÜSS", s.to_uppercase());
1871 /// ```
1872 #[must_use = "this returns the uppercase string as a new CompactString, \
1873 without modifying the original"]
1874 pub fn to_uppercase(&self) -> Self {
1875 Self::from_str_to_uppercase(self.as_str())
1876 }
1877
1878 /// Returns the uppercase equivalent of this string slice, as a new [`CompactString`].
1879 ///
1880 /// 'Uppercase' is defined according to the terms of the Unicode Derived Core Property
1881 /// `Uppercase`.
1882 ///
1883 /// Since some characters can expand into multiple characters when changing
1884 /// the case, this function returns a [`CompactString`] instead of modifying the
1885 /// parameter in-place.
1886 ///
1887 /// # Examples
1888 ///
1889 /// Basic usage:
1890 ///
1891 /// ```
1892 /// use compact_str::CompactString;
1893 ///
1894 /// assert_eq!("HELLO", CompactString::from_str_to_uppercase("hello"));
1895 /// ```
1896 ///
1897 /// Scripts without case are not changed:
1898 ///
1899 /// ```
1900 /// use compact_str::CompactString;
1901 ///
1902 /// let new_year = "农历新年";
1903 /// assert_eq!(new_year, CompactString::from_str_to_uppercase(new_year));
1904 /// ```
1905 ///
1906 /// One character can become multiple:
1907 /// ```
1908 /// use compact_str::CompactString;
1909 ///
1910 /// assert_eq!("TSCHÜSS", CompactString::from_str_to_uppercase("tschüß"));
1911 /// ```
1912 #[must_use = "this returns the uppercase string as a new CompactString, \
1913 without modifying the original"]
1914 pub fn from_str_to_uppercase(input: &str) -> Self {
1915 let mut out = convert_while_ascii(input.as_bytes(), u8::to_ascii_uppercase);
1916
1917 // Safety: we know this is a valid char boundary since
1918 // out.len() is only progressed if ascii bytes are found
1919 let rest = unsafe { input.get_unchecked(out.len()..) };
1920
1921 for c in rest.chars() {
1922 out.extend(c.to_uppercase());
1923 }
1924
1925 out
1926 }
1927}
1928
1929/// Converts the bytes while the bytes are still ascii.
1930/// For better average performance, this is happens in chunks of `2*size_of::<usize>()`.
1931/// Returns a vec with the converted bytes.
1932///
1933/// Copied from https://doc.rust-lang.org/nightly/src/alloc/str.rs.html#623-666
1934#[inline]
1935fn convert_while_ascii(b: &[u8], convert: fn(&u8) -> u8) -> CompactString {
1936 let mut out = CompactString::with_capacity(b.len());
1937
1938 const USIZE_SIZE: usize = mem::size_of::<usize>();
1939 const MAGIC_UNROLL: usize = 2;
1940 const N: usize = USIZE_SIZE * MAGIC_UNROLL;
1941 const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; USIZE_SIZE]);
1942
1943 let mut i = 0;
1944 unsafe {
1945 while i + N <= b.len() {
1946 // Safety: we have checks the sizes `b` and `out` to know that our
1947 let in_chunk = b.get_unchecked(i..i + N);
1948 let out_chunk = out.spare_capacity_mut().get_unchecked_mut(i..i + N);
1949
1950 let mut bits = 0;
1951 for j in 0..MAGIC_UNROLL {
1952 // read the bytes 1 usize at a time (unaligned since we haven't checked the
1953 // alignment) safety: in_chunk is valid bytes in the range
1954 bits |= in_chunk.as_ptr().cast::<usize>().add(j).read_unaligned();
1955 }
1956 // if our chunks aren't ascii, then return only the prior bytes as init
1957 if bits & NONASCII_MASK != 0 {
1958 break;
1959 }
1960
1961 // perform the case conversions on N bytes (gets heavily autovec'd)
1962 for j in 0..N {
1963 // safety: in_chunk and out_chunk is valid bytes in the range
1964 let out = out_chunk.get_unchecked_mut(j);
1965 out.write(convert(in_chunk.get_unchecked(j)));
1966 }
1967
1968 // mark these bytes as initialised
1969 i += N;
1970 }
1971 out.set_len(i);
1972 }
1973
1974 out
1975}
1976
1977impl Clone for CompactString {
1978 #[inline]
1979 fn clone(&self) -> Self {
1980 Self(self.0.clone())
1981 }
1982
1983 #[inline]
1984 fn clone_from(&mut self, source: &Self) {
1985 self.0.clone_from(&source.0)
1986 }
1987}
1988
1989impl Default for CompactString {
1990 #[inline]
1991 fn default() -> Self {
1992 CompactString::const_new("")
1993 }
1994}
1995
1996impl Deref for CompactString {
1997 type Target = str;
1998
1999 #[inline]
2000 fn deref(&self) -> &str {
2001 self.as_str()
2002 }
2003}
2004
2005impl DerefMut for CompactString {
2006 #[inline]
2007 fn deref_mut(&mut self) -> &mut str {
2008 self.as_mut_str()
2009 }
2010}
2011
2012impl AsRef<str> for CompactString {
2013 #[inline]
2014 fn as_ref(&self) -> &str {
2015 self.as_str()
2016 }
2017}
2018
2019#[cfg(feature = "std")]
2020impl AsRef<OsStr> for CompactString {
2021 #[inline]
2022 fn as_ref(&self) -> &OsStr {
2023 OsStr::new(self.as_str())
2024 }
2025}
2026
2027impl AsRef<[u8]> for CompactString {
2028 #[inline]
2029 fn as_ref(&self) -> &[u8] {
2030 self.as_bytes()
2031 }
2032}
2033
2034impl Borrow<str> for CompactString {
2035 #[inline]
2036 fn borrow(&self) -> &str {
2037 self.as_str()
2038 }
2039}
2040
2041impl BorrowMut<str> for CompactString {
2042 #[inline]
2043 fn borrow_mut(&mut self) -> &mut str {
2044 self.as_mut_str()
2045 }
2046}
2047
2048impl Eq for CompactString {}
2049
2050impl<T: AsRef<str> + ?Sized> PartialEq<T> for CompactString {
2051 fn eq(&self, other: &T) -> bool {
2052 self.as_str() == other.as_ref()
2053 }
2054}
2055
2056impl PartialEq<CompactString> for &CompactString {
2057 fn eq(&self, other: &CompactString) -> bool {
2058 self.as_str() == other.as_str()
2059 }
2060}
2061
2062impl PartialEq<CompactString> for String {
2063 fn eq(&self, other: &CompactString) -> bool {
2064 self.as_str() == other.as_str()
2065 }
2066}
2067
2068impl PartialEq<&CompactString> for String {
2069 fn eq(&self, other: &&CompactString) -> bool {
2070 self.as_str() == other.as_str()
2071 }
2072}
2073
2074impl PartialEq<CompactString> for &String {
2075 fn eq(&self, other: &CompactString) -> bool {
2076 self.as_str() == other.as_str()
2077 }
2078}
2079
2080impl PartialEq<CompactString> for str {
2081 fn eq(&self, other: &CompactString) -> bool {
2082 self == other.as_str()
2083 }
2084}
2085
2086impl PartialEq<&'_ CompactString> for str {
2087 fn eq(&self, other: &&CompactString) -> bool {
2088 self == other.as_str()
2089 }
2090}
2091
2092impl PartialEq<CompactString> for &str {
2093 fn eq(&self, other: &CompactString) -> bool {
2094 *self == other.as_str()
2095 }
2096}
2097
2098impl PartialEq<CompactString> for &&str {
2099 fn eq(&self, other: &CompactString) -> bool {
2100 **self == other.as_str()
2101 }
2102}
2103
2104impl PartialEq<CompactString> for Cow<'_, str> {
2105 fn eq(&self, other: &CompactString) -> bool {
2106 *self == other.as_str()
2107 }
2108}
2109
2110impl PartialEq<CompactString> for &Cow<'_, str> {
2111 fn eq(&self, other: &CompactString) -> bool {
2112 *self == other.as_str()
2113 }
2114}
2115
2116impl PartialEq<String> for &CompactString {
2117 fn eq(&self, other: &String) -> bool {
2118 self.as_str() == other.as_str()
2119 }
2120}
2121
2122impl PartialEq<Cow<'_, str>> for &CompactString {
2123 fn eq(&self, other: &Cow<'_, str>) -> bool {
2124 self.as_str() == other
2125 }
2126}
2127
2128impl Ord for CompactString {
2129 fn cmp(&self, other: &Self) -> Ordering {
2130 self.as_str().cmp(other.as_str())
2131 }
2132}
2133
2134impl PartialOrd for CompactString {
2135 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2136 Some(self.cmp(other))
2137 }
2138}
2139
2140impl Hash for CompactString {
2141 fn hash<H: Hasher>(&self, state: &mut H) {
2142 self.as_str().hash(state)
2143 }
2144}
2145
2146impl<'a> From<&'a str> for CompactString {
2147 #[inline]
2148 #[track_caller]
2149 fn from(s: &'a str) -> Self {
2150 CompactString::new(s)
2151 }
2152}
2153
2154impl From<String> for CompactString {
2155 #[inline]
2156 #[track_caller]
2157 fn from(s: String) -> Self {
2158 let repr = Repr::from_string(s, true).unwrap_with_msg();
2159 CompactString(repr)
2160 }
2161}
2162
2163impl<'a> From<&'a String> for CompactString {
2164 #[inline]
2165 #[track_caller]
2166 fn from(s: &'a String) -> Self {
2167 CompactString::new(s)
2168 }
2169}
2170
2171impl<'a> From<Cow<'a, str>> for CompactString {
2172 fn from(cow: Cow<'a, str>) -> Self {
2173 match cow {
2174 Cow::Borrowed(s) => s.into(),
2175 // we separate these two so we can re-use the underlying buffer in the owned case
2176 Cow::Owned(s) => s.into(),
2177 }
2178 }
2179}
2180
2181impl From<Box<str>> for CompactString {
2182 #[inline]
2183 #[track_caller]
2184 fn from(b: Box<str>) -> Self {
2185 let s = b.into_string();
2186 let repr = Repr::from_string(s, true).unwrap_with_msg();
2187 CompactString(repr)
2188 }
2189}
2190
2191impl From<CompactString> for String {
2192 #[inline]
2193 fn from(s: CompactString) -> Self {
2194 s.into_string()
2195 }
2196}
2197
2198impl From<CompactString> for Cow<'_, str> {
2199 #[inline]
2200 fn from(s: CompactString) -> Self {
2201 if let Some(s) = s.as_static_str() {
2202 Self::Borrowed(s)
2203 } else {
2204 Self::Owned(s.into_string())
2205 }
2206 }
2207}
2208
2209impl<'a> From<&'a CompactString> for Cow<'a, str> {
2210 #[inline]
2211 fn from(s: &'a CompactString) -> Self {
2212 Self::Borrowed(s)
2213 }
2214}
2215
2216#[cfg(target_has_atomic = "ptr")]
2217impl From<CompactString> for alloc::sync::Arc<str> {
2218 fn from(value: CompactString) -> Self {
2219 Self::from(value.as_str())
2220 }
2221}
2222
2223impl From<CompactString> for alloc::rc::Rc<str> {
2224 fn from(value: CompactString) -> Self {
2225 Self::from(value.as_str())
2226 }
2227}
2228
2229#[cfg(feature = "std")]
2230impl From<CompactString> for Box<dyn std::error::Error + Send + Sync> {
2231 fn from(value: CompactString) -> Self {
2232 struct StringError(CompactString);
2233
2234 impl std::error::Error for StringError {
2235 #[allow(deprecated)]
2236 fn description(&self) -> &str {
2237 &self.0
2238 }
2239 }
2240
2241 impl fmt::Display for StringError {
2242 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2243 fmt::Display::fmt(&self.0, f)
2244 }
2245 }
2246
2247 // Purposefully skip printing "StringError(..)"
2248 impl fmt::Debug for StringError {
2249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2250 fmt::Debug::fmt(&self.0, f)
2251 }
2252 }
2253
2254 Box::new(StringError(value))
2255 }
2256}
2257
2258#[cfg(feature = "std")]
2259impl From<CompactString> for Box<dyn std::error::Error> {
2260 fn from(value: CompactString) -> Self {
2261 let err1: Box<dyn std::error::Error + Send + Sync> = From::from(value);
2262 let err2: Box<dyn std::error::Error> = err1;
2263 err2
2264 }
2265}
2266
2267impl From<CompactString> for Box<str> {
2268 fn from(value: CompactString) -> Self {
2269 if value.is_heap_allocated() {
2270 value.into_string().into_boxed_str()
2271 } else {
2272 Box::from(value.as_str())
2273 }
2274 }
2275}
2276
2277#[cfg(feature = "std")]
2278impl From<CompactString> for std::ffi::OsString {
2279 fn from(value: CompactString) -> Self {
2280 Self::from(value.into_string())
2281 }
2282}
2283
2284#[cfg(feature = "std")]
2285impl From<CompactString> for std::path::PathBuf {
2286 fn from(value: CompactString) -> Self {
2287 Self::from(std::ffi::OsString::from(value))
2288 }
2289}
2290
2291#[cfg(feature = "std")]
2292impl AsRef<std::path::Path> for CompactString {
2293 fn as_ref(&self) -> &std::path::Path {
2294 std::path::Path::new(self.as_str())
2295 }
2296}
2297
2298impl From<CompactString> for alloc::vec::Vec<u8> {
2299 fn from(value: CompactString) -> Self {
2300 if value.is_heap_allocated() {
2301 value.into_string().into_bytes()
2302 } else {
2303 value.as_bytes().to_vec()
2304 }
2305 }
2306}
2307
2308impl FromStr for CompactString {
2309 type Err = core::convert::Infallible;
2310 fn from_str(s: &str) -> Result<CompactString, Self::Err> {
2311 Ok(CompactString::from(s))
2312 }
2313}
2314
2315impl fmt::Debug for CompactString {
2316 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2317 fmt::Debug::fmt(self.as_str(), f)
2318 }
2319}
2320
2321impl fmt::Display for CompactString {
2322 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2323 fmt::Display::fmt(self.as_str(), f)
2324 }
2325}
2326
2327impl FromIterator<char> for CompactString {
2328 fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
2329 let repr = iter.into_iter().collect();
2330 CompactString(repr)
2331 }
2332}
2333
2334impl<'a> FromIterator<&'a char> for CompactString {
2335 fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
2336 let repr = iter.into_iter().collect();
2337 CompactString(repr)
2338 }
2339}
2340
2341impl<'a> FromIterator<&'a str> for CompactString {
2342 fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
2343 let repr = iter.into_iter().collect();
2344 CompactString(repr)
2345 }
2346}
2347
2348impl FromIterator<Box<str>> for CompactString {
2349 fn from_iter<T: IntoIterator<Item = Box<str>>>(iter: T) -> Self {
2350 let repr = iter.into_iter().collect();
2351 CompactString(repr)
2352 }
2353}
2354
2355impl<'a> FromIterator<Cow<'a, str>> for CompactString {
2356 fn from_iter<T: IntoIterator<Item = Cow<'a, str>>>(iter: T) -> Self {
2357 let repr = iter.into_iter().collect();
2358 CompactString(repr)
2359 }
2360}
2361
2362impl FromIterator<String> for CompactString {
2363 fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
2364 let repr = iter.into_iter().collect();
2365 CompactString(repr)
2366 }
2367}
2368
2369impl FromIterator<CompactString> for CompactString {
2370 fn from_iter<T: IntoIterator<Item = CompactString>>(iter: T) -> Self {
2371 let repr = iter.into_iter().collect();
2372 CompactString(repr)
2373 }
2374}
2375
2376impl FromIterator<CompactString> for String {
2377 fn from_iter<T: IntoIterator<Item = CompactString>>(iter: T) -> Self {
2378 let mut iterator = iter.into_iter();
2379 match iterator.next() {
2380 None => String::new(),
2381 Some(buf) => {
2382 let mut buf = buf.into_string();
2383 buf.extend(iterator);
2384 buf
2385 }
2386 }
2387 }
2388}
2389
2390impl FromIterator<CompactString> for Cow<'_, str> {
2391 fn from_iter<T: IntoIterator<Item = CompactString>>(iter: T) -> Self {
2392 String::from_iter(iter).into()
2393 }
2394}
2395
2396impl Extend<char> for CompactString {
2397 fn extend<T: IntoIterator<Item = char>>(&mut self, iter: T) {
2398 self.0.extend(iter)
2399 }
2400}
2401
2402impl<'a> Extend<&'a char> for CompactString {
2403 fn extend<T: IntoIterator<Item = &'a char>>(&mut self, iter: T) {
2404 self.0.extend(iter)
2405 }
2406}
2407
2408impl<'a> Extend<&'a str> for CompactString {
2409 fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T) {
2410 self.0.extend(iter)
2411 }
2412}
2413
2414impl Extend<Box<str>> for CompactString {
2415 fn extend<T: IntoIterator<Item = Box<str>>>(&mut self, iter: T) {
2416 self.0.extend(iter)
2417 }
2418}
2419
2420impl<'a> Extend<Cow<'a, str>> for CompactString {
2421 fn extend<T: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: T) {
2422 iter.into_iter().for_each(move |s| self.push_str(&s));
2423 }
2424}
2425
2426impl Extend<String> for CompactString {
2427 fn extend<T: IntoIterator<Item = String>>(&mut self, iter: T) {
2428 self.0.extend(iter)
2429 }
2430}
2431
2432impl Extend<CompactString> for String {
2433 fn extend<T: IntoIterator<Item = CompactString>>(&mut self, iter: T) {
2434 for s in iter {
2435 self.push_str(&s);
2436 }
2437 }
2438}
2439
2440impl Extend<CompactString> for CompactString {
2441 fn extend<T: IntoIterator<Item = CompactString>>(&mut self, iter: T) {
2442 for s in iter {
2443 self.push_str(&s);
2444 }
2445 }
2446}
2447
2448impl Extend<CompactString> for Cow<'_, str> {
2449 fn extend<T: IntoIterator<Item = CompactString>>(&mut self, iter: T) {
2450 self.to_mut().extend(iter);
2451 }
2452}
2453
2454impl fmt::Write for CompactString {
2455 fn write_str(&mut self, s: &str) -> fmt::Result {
2456 self.push_str(s);
2457 Ok(())
2458 }
2459
2460 fn write_fmt(mut self: &mut Self, args: fmt::Arguments<'_>) -> fmt::Result {
2461 match args.as_str() {
2462 Some(s) => {
2463 if self.is_empty() && !self.is_heap_allocated() {
2464 // Since self is currently an empty inline variant or
2465 // an empty `StaticStr` variant, constructing a new one
2466 // with `Self::const_new` is more efficient since
2467 // it is guaranteed to be O(1).
2468 *self = Self::const_new(s);
2469 } else {
2470 self.push_str(s);
2471 }
2472 Ok(())
2473 }
2474 None => fmt::write(&mut self, args),
2475 }
2476 }
2477}
2478
2479impl Add<&str> for CompactString {
2480 type Output = Self;
2481 fn add(mut self, rhs: &str) -> Self::Output {
2482 self.push_str(rhs);
2483 self
2484 }
2485}
2486
2487impl AddAssign<&str> for CompactString {
2488 fn add_assign(&mut self, rhs: &str) {
2489 self.push_str(rhs);
2490 }
2491}
2492
2493/// A possible error value when converting a [`CompactString`] from a UTF-16 byte slice.
2494///
2495/// This type is the error type for the [`from_utf16`] method on [`CompactString`].
2496///
2497/// [`from_utf16`]: CompactString::from_utf16
2498/// # Examples
2499///
2500/// Basic usage:
2501///
2502/// ```
2503/// # use compact_str::CompactString;
2504/// // 𝄞mu<invalid>ic
2505/// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075,
2506/// 0xD800, 0x0069, 0x0063];
2507///
2508/// assert!(CompactString::from_utf16(v).is_err());
2509/// ```
2510#[derive(Copy, Clone, Debug)]
2511pub struct Utf16Error(());
2512
2513impl fmt::Display for Utf16Error {
2514 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2515 fmt::Display::fmt("invalid utf-16: lone surrogate found", f)
2516 }
2517}
2518
2519/// An iterator over the exacted data by [`CompactString::drain()`].
2520///
2521/// Note: this is deliberately not `#[must_use]`. Dropping a `Drain` still removes the
2522/// selected range from the source `CompactString` (see the `Drop` impl), so calling
2523/// `drain(range)` purely to delete a range, without consuming the iterator, is a valid
2524/// and common use, mirroring `alloc::string::Drain`.
2525pub struct Drain<'a> {
2526 compact_string: *mut CompactString,
2527 start: usize,
2528 end: usize,
2529 chars: core::str::Chars<'a>,
2530}
2531
2532// SAFETY: Drain keeps the lifetime of the CompactString it belongs to.
2533unsafe impl Send for Drain<'_> {}
2534unsafe impl Sync for Drain<'_> {}
2535
2536impl fmt::Debug for Drain<'_> {
2537 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2538 f.debug_tuple("Drain").field(&self.as_str()).finish()
2539 }
2540}
2541
2542impl fmt::Display for Drain<'_> {
2543 #[inline]
2544 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2545 f.write_str(self.as_str())
2546 }
2547}
2548
2549impl Drop for Drain<'_> {
2550 #[inline]
2551 fn drop(&mut self) {
2552 // SAFETY: Drain keeps a mutable reference to compact_string, so one one else can access
2553 // the CompactString, but this function right now. CompactString::drain() ensured
2554 // that the new extracted range does not split a UTF-8 character.
2555 unsafe { (*self.compact_string).replace_range_shrink(self.start, self.end, "") };
2556 }
2557}
2558
2559impl Drain<'_> {
2560 /// The remaining, unconsumed characters of the extracted substring.
2561 #[inline]
2562 pub fn as_str(&self) -> &str {
2563 self.chars.as_str()
2564 }
2565}
2566
2567impl Deref for Drain<'_> {
2568 type Target = str;
2569
2570 #[inline]
2571 fn deref(&self) -> &Self::Target {
2572 self.as_str()
2573 }
2574}
2575
2576impl Iterator for Drain<'_> {
2577 type Item = char;
2578
2579 #[inline]
2580 fn next(&mut self) -> Option<char> {
2581 self.chars.next()
2582 }
2583
2584 #[inline]
2585 fn count(self) -> usize {
2586 // <Chars as Iterator>::count() is specialized, and cloning is trivial.
2587 self.chars.clone().count()
2588 }
2589
2590 fn size_hint(&self) -> (usize, Option<usize>) {
2591 self.chars.size_hint()
2592 }
2593
2594 #[inline]
2595 fn last(mut self) -> Option<char> {
2596 self.chars.next_back()
2597 }
2598}
2599
2600impl DoubleEndedIterator for Drain<'_> {
2601 #[inline]
2602 fn next_back(&mut self) -> Option<char> {
2603 self.chars.next_back()
2604 }
2605}
2606
2607impl FusedIterator for Drain<'_> {}
2608
2609/// A possible error value if allocating or resizing a [`CompactString`] failed.
2610#[derive(Debug, Clone, Copy, PartialEq)]
2611pub struct ReserveError(());
2612
2613impl fmt::Display for ReserveError {
2614 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2615 f.write_str("Cannot allocate memory to hold CompactString")
2616 }
2617}
2618
2619#[cfg(feature = "std")]
2620#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
2621impl std::error::Error for ReserveError {}
2622
2623/// A possible error value if [`ToCompactString::try_to_compact_string()`] failed.
2624#[derive(Debug, Clone, Copy, PartialEq)]
2625#[non_exhaustive]
2626pub enum ToCompactStringError {
2627 /// Cannot allocate memory to hold CompactString
2628 Reserve(ReserveError),
2629 /// [`Display::fmt()`][core::fmt::Display::fmt] returned an error
2630 Fmt(fmt::Error),
2631}
2632
2633impl fmt::Display for ToCompactStringError {
2634 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2635 match self {
2636 ToCompactStringError::Reserve(err) => err.fmt(f),
2637 ToCompactStringError::Fmt(err) => err.fmt(f),
2638 }
2639 }
2640}
2641
2642impl From<ReserveError> for ToCompactStringError {
2643 #[inline]
2644 fn from(value: ReserveError) -> Self {
2645 Self::Reserve(value)
2646 }
2647}
2648
2649impl From<fmt::Error> for ToCompactStringError {
2650 #[inline]
2651 fn from(value: fmt::Error) -> Self {
2652 Self::Fmt(value)
2653 }
2654}
2655
2656#[cfg(feature = "std")]
2657#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
2658impl std::error::Error for ToCompactStringError {
2659 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
2660 match self {
2661 ToCompactStringError::Reserve(err) => Some(err),
2662 ToCompactStringError::Fmt(err) => Some(err),
2663 }
2664 }
2665}
2666
2667trait UnwrapWithMsg {
2668 type T;
2669
2670 fn unwrap_with_msg(self) -> Self::T;
2671}
2672
2673impl<T, E: fmt::Display> UnwrapWithMsg for Result<T, E> {
2674 type T = T;
2675
2676 #[inline(always)]
2677 #[track_caller]
2678 fn unwrap_with_msg(self) -> T {
2679 match self {
2680 Ok(value) => value,
2681 Err(err) => unwrap_with_msg_fail(err),
2682 }
2683 }
2684}
2685
2686#[inline(never)]
2687#[cold]
2688#[track_caller]
2689fn unwrap_with_msg_fail<E: fmt::Display>(error: E) -> ! {
2690 panic!("{error}")
2691}
2692
2693static_assertions::assert_eq_size!(CompactString, String);
2694static_assertions::assert_eq_size!(Option<CompactString>, CompactString);