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