Skip to main content

omp_core/
str.rs

1//! Small string optimization with stack allocation for short strings.
2//!
3//! `Str` stores strings up to 23 bytes inline, avoiding heap allocation for
4//! typical short strings. Longer strings use reference-counted heap storage
5//! with O(1) cloning.
6
7use std::{
8	borrow::{Borrow, BorrowMut, Cow},
9	boxed::Box,
10	cmp::Ordering,
11	convert::Infallible,
12	fmt,
13	hash::{self, Hash, Hasher},
14	iter::FromIterator,
15	mem,
16	ops::{Add, Deref, DerefMut, Index},
17	ptr, str,
18	string::String,
19	sync::Arc,
20};
21
22use bytes::{Bytes, BytesMut};
23use bytes_utils::{Str as BytesStr, StrMut as BytesStrMut, string::StorageMut};
24
25/// A `Str` is a string type that has the following properties:
26///
27/// * `size_of::<Str>() == 32`
28/// * `Clone` is `O(1)`
29/// * Strings are stack-allocated if they are:
30///     * Up to 23 bytes long
31/// * Additionally, a `Str` can be explicitly created from a `&'static str`
32///   without allocation
33///
34/// Unlike `String`, however, `Str` is immutable. The primary use case for
35#[derive(Default, Clone)]
36#[repr(transparent)]
37pub struct Str(Repr<BytesStr>);
38
39/// An error type for UTF-8 validation.
40pub type Utf8Error = bytes_utils::string::Utf8Error<Bytes>;
41
42/// An error type for UTF-8 validation.
43pub type Utf8ErrorMut = bytes_utils::string::Utf8Error<BytesMut>;
44
45impl Str {
46	/// Constructs a `Str` from a `Bytes` object without checking for UTF-8
47	/// validity.
48	///
49	/// # Safety
50	///
51	/// The caller must ensure that the bytes are valid UTF-8. If this condition
52	/// is not met, the behavior is undefined.
53	#[inline]
54	pub unsafe fn from_utf8_unchecked_owned(u: impl Into<Bytes>) -> Self {
55		// SAFETY: The caller guarantees that the bytes are valid UTF-8.
56		Self(Repr::Heap(unsafe { BytesStr::from_inner_unchecked(u.into()) }))
57	}
58
59	/// Promotes an inline representation to a heap representation in place.
60	///
61	/// This function converts the internal representation of the `Str` from
62	/// inline to heap and returns a reference to the [`BytesStr`].
63	#[inline]
64	pub fn promote(&mut self) -> &mut BytesStr {
65		if let Repr::Inline(buf) = &mut self.0 {
66			self.0 = Repr::Heap(buf.as_str().into());
67		}
68		let Repr::Heap(data) = &mut self.0 else {
69			unreachable!();
70		};
71		data
72	}
73
74	/// Constructs a `Str` from a byte slice without checking for UTF-8
75	/// validity.
76	///
77	/// # Safety
78	///
79	/// The caller must ensure that the bytes are valid UTF-8. If this condition
80	/// is not met, the behavior is undefined.
81	#[inline]
82	pub unsafe fn from_utf8_unchecked(u: &[u8]) -> Self {
83		// SAFETY: The caller guarantees that the bytes are valid UTF-8.
84		Self::new(unsafe { str::from_utf8_unchecked(u) })
85	}
86
87	/// Constructs a `Str` from a `Bytes` object, checking for UTF-8
88	/// validity.
89	///
90	/// Returns an error if the bytes are not valid UTF-8.
91	#[inline]
92	pub fn from_utf8_owned(u: impl Into<Bytes>) -> Result<Self, Utf8Error> {
93		Ok(Self(Repr::Heap(BytesStr::from_inner(u.into())?)))
94	}
95
96	/// Constructs a `Str` from a byte slice, checking for UTF-8 validity.
97	///
98	/// Returns an error if the bytes are not valid UTF-8.
99	#[inline]
100	pub fn from_utf8(u: &[u8]) -> Result<Self, str::Utf8Error> {
101		Ok(Self::new(str::from_utf8(u)?))
102	}
103
104	/// Constructs a `Str` from bytes, replacing invalid UTF-8 sequences with
105	/// `U+FFFD`.
106	///
107	/// When repairs are needed, the repaired string allocation is transferred
108	/// into the result.
109	#[inline]
110	pub fn from_utf8_lossy(u: &[u8]) -> Self {
111		match String::from_utf8_lossy(u) {
112			Cow::Borrowed(text) => Self::new(text),
113			Cow::Owned(text) => Self::from(text),
114		}
115	}
116
117	/// Constructs an inline variant of `Str`.
118	///
119	/// This never allocates.
120	///
121	/// # Panics
122	///
123	/// Panics if `text.len() > 23`.
124	#[inline]
125	pub fn new_inline(text: &str) -> Self {
126		Self(Repr::new_inline(text).expect("len <= INLINE_CAP"))
127	}
128
129	/// Constructs a `Str` from a statically allocated string.
130	///
131	/// This never allocates.
132	#[inline(always)]
133	pub const fn new_static(text: &'static str) -> Self {
134		// NOTE: this never uses the inline storage; if a canonical
135		// representation is needed, we could check for `len() < INLINE_CAP`
136		// and call `new_inline`, but this would mean an extra branch.
137		Self(Repr::Heap(BytesStr::from_static(text)))
138	}
139
140	/// Constructs a `Str` from a `str`, heap-allocating if necessary.
141	#[inline(always)]
142	pub fn new(text: impl AsRef<str>) -> Self {
143		Self(Repr::copy_from_str(text.as_ref()))
144	}
145
146	/// Returns a `&str` slice of this `Str`.
147	#[inline(always)]
148	pub fn as_str(&self) -> &str {
149		self.0.as_str()
150	}
151
152	/// Returns the length of `self` in bytes.
153	#[inline(always)]
154	pub fn len(&self) -> usize {
155		self.0.len()
156	}
157
158	/// Returns `true` if `self` has a length of zero bytes.
159	#[inline(always)]
160	pub fn is_empty(&self) -> bool {
161		self.0.is_empty()
162	}
163
164	/// Returns `true` if `self` is heap-allocated.
165	#[inline(always)]
166	pub const fn is_spilled(&self) -> bool {
167		matches!(self.0, Repr::Heap(..))
168	}
169
170	/// Returns `true` if the string is unique.
171	#[inline(always)]
172	pub fn is_unique(&self) -> bool {
173		match &self.0 {
174			Repr::Heap(data) => data.inner().is_unique(),
175			Repr::Inline(_) => true,
176		}
177	}
178
179	/// Strips a prefix from the string, returning the remainder as a new
180	/// `Str`. Returns `None` if the string doesn't start with the prefix.
181	#[inline]
182	pub fn strip_prefix(&self, prefix: &str) -> Option<Self> {
183		let s = self.as_str();
184		s.strip_prefix(prefix).map(|r| self.slice_ref(r))
185	}
186
187	/// Strips a suffix from the string, returning the remainder as a new
188	/// `Str`. Returns `None` if the string doesn't end with the suffix.
189	#[inline]
190	pub fn strip_suffix(&self, suffix: &str) -> Option<Self> {
191		let s = self.as_str();
192		s.strip_suffix(suffix).map(|r| self.slice_ref(r))
193	}
194
195	/// Returns a substring as a new `Str`.
196	/// For heap-allocated strings, this is a zero-copy operation.
197	///
198	/// # Panics
199	/// Panics if the range is not on valid UTF-8 boundaries.
200	#[inline]
201	pub fn slice<R>(&self, range: R) -> Self
202	where
203		str: Index<R, Output = str>,
204	{
205		match &self.0 {
206			Repr::Heap(data) => Self(Repr::Heap(data.slice(range))),
207			_ => Self::new_inline(&self[range]),
208		}
209	}
210
211	/// Extracts owned representation of the slice passed.
212	/// For heap-allocated strings, this is a zero-copy operation.
213	#[inline]
214	pub fn slice_ref(&self, subset: &str) -> Self {
215		match &self.0 {
216			Repr::Heap(data) => Self(Repr::Heap(data.slice_ref(subset))),
217			_ => Self::new_inline(subset),
218		}
219	}
220
221	/// Splits the string at the given byte index and returns two `Str`s.
222	/// For heap-allocated strings, this creates two zero-copy references.
223	///
224	/// # Panics
225	/// Panics if `at` is not on a UTF-8 character boundary.
226	#[inline]
227	pub fn split_at(&self, at: usize) -> (Self, Self) {
228		match &self.0 {
229			Repr::Heap(data) => {
230				let (left, right) = data.clone().split_at_bytes(at);
231				(Self(Repr::Heap(left)), Self(Repr::Heap(right)))
232			},
233			Repr::Inline(buf) => {
234				let (left, right) = buf.split_at(at);
235				(Self::new_inline(left), Self::new_inline(right))
236			},
237		}
238	}
239
240	/// Returns a string with leading whitespace removed.
241	/// For heap strings, this is zero-copy when possible.
242	#[inline]
243	pub fn trim_start(&self) -> Self {
244		let trimmed = self.as_str().trim_start();
245		self.slice_ref(trimmed)
246	}
247
248	/// Returns a string with trailing whitespace removed.
249	/// For heap strings, this is zero-copy when possible.
250	#[inline]
251	pub fn trim_end(&self) -> Self {
252		let trimmed = self.as_str().trim_end();
253		self.slice_ref(trimmed)
254	}
255
256	/// Returns a string with leading and trailing whitespace removed.
257	/// For heap strings, this is zero-copy when possible.
258	#[inline]
259	pub fn trim(&self) -> Self {
260		let trimmed = self.as_str().trim();
261		self.slice_ref(trimmed)
262	}
263
264	/// Truncates the `Str` to the specified length.
265	///
266	/// If `len` is greater than the current length, this has no effect.
267	///
268	/// # Panics
269	///
270	/// Panics if `len` is greater than the current length of the `Str` or if
271	/// `len` is not on a valid UTF-8 character boundary.
272	#[inline]
273	pub fn truncate(&mut self, len: usize) {
274		match &mut self.0 {
275			Repr::Inline(buf) => {
276				buf.truncate(len);
277			},
278			Repr::Heap(heap) => {
279				assert!(heap.is_char_boundary(len), "Index is not on a char boundary");
280				// SAFETY: The bytes are valid UTF-8 because they originated from a
281				// heap-allocated string that was previously validated. Truncating at a
282				// char boundary (verified by the assert above) preserves UTF-8 validity.
283				unsafe {
284					let mut bytes = mem::take(heap).into_inner();
285					bytes.truncate(len);
286					*heap = BytesStr::from_inner_unchecked(bytes);
287				}
288			},
289		}
290	}
291
292	/// Splits on the given separator and returns an iterator of `Str`s.
293	/// For heap strings, the splits are zero-copy references.
294	pub fn split<'s>(
295		&'s self,
296		separator: &'s str,
297	) -> impl Clone + std::iter::FusedIterator<Item = Self> + 's {
298		self
299			.as_str()
300			.split(separator)
301			.map(move |s| self.slice_ref(s))
302	}
303
304	/// Converts the string to ASCII lowercase.
305	///
306	/// Reuses the allocation when uniquely owned; otherwise copies.
307	pub fn into_ascii_lowercase(self) -> Self {
308		let mut buf = StrMut::from(self);
309		buf.make_ascii_lowercase();
310		buf.freeze()
311	}
312
313	/// Converts the string to ASCII uppercase.
314	///
315	/// Reuses the allocation when uniquely owned; otherwise copies.
316	pub fn into_ascii_uppercase(self) -> Self {
317		let mut buf = StrMut::from(self);
318		buf.make_ascii_uppercase();
319		buf.freeze()
320	}
321
322	/// Returns a byte slice of this `Str`.
323	#[inline(always)]
324	pub fn as_bytes(&self) -> &[u8] {
325		self.as_str().as_bytes()
326	}
327
328	/// Tries to convert this `Str` into a `StrMut`.
329	#[inline]
330	pub fn try_into_mut(self) -> Result<StrMut, Self> {
331		match self.0 {
332			Repr::Heap(data) => match data.into_inner().try_into_mut() {
333				// SAFETY: The data is valid UTF-8 because it came from a BytesStr,
334				// and BytesMut preserves the UTF-8 bytes when converted.
335				Ok(data) => Ok(StrMut(Repr::Heap(unsafe { BytesStrMut::from_inner_unchecked(data) }))),
336				// SAFETY: If try_into_mut fails, we reconstruct the original BytesStr from
337				// the returned Bytes. The bytes are still valid UTF-8.
338				Err(e) => Err(Self(Repr::Heap(unsafe { BytesStr::from_inner_unchecked(e) }))),
339			},
340			Repr::Inline(buf) => Ok(StrMut(Repr::Inline(buf))),
341		}
342	}
343}
344
345/// Extension trait for `str` to provide `_str` versions of methods that
346/// return an allocated `String`.
347pub trait StrExt {
348	/// Converts the string to lowercase using ASCII rules and returns a
349	/// `Str`.
350	///
351	/// This is a `_str` version of [`str::to_ascii_lowercase`].
352	///
353	/// # Examples
354	///
355	/// ```
356	/// use omp_core::str::StrExt;
357	///
358	/// let s = "HELLO";
359	/// let string = s.to_ascii_lowercase_str();
360	/// assert_eq!(string, "hello");
361	/// ```
362	fn to_ascii_lowercase_str(&self) -> Str;
363
364	/// Converts the string to uppercase using ASCII rules and returns a
365	/// `Str`.
366	///
367	/// This is a `_str` version of [`str::to_ascii_uppercase`].
368	///
369	/// # Examples
370	///
371	/// ```
372	/// use omp_core::str::StrExt;
373	///
374	/// let s = "hello";
375	/// let string = s.to_ascii_uppercase_str();
376	/// assert_eq!(string, "HELLO");
377	/// ```
378	fn to_ascii_uppercase_str(&self) -> Str;
379}
380
381impl StrExt for str {
382	fn to_ascii_lowercase_str(&self) -> Str {
383		let mut s = StrMut::new(self);
384		s.make_ascii_lowercase();
385		s.freeze()
386	}
387
388	fn to_ascii_uppercase_str(&self) -> Str {
389		let mut s = StrMut::new(self);
390		s.make_ascii_uppercase();
391		s.freeze()
392	}
393}
394
395// ============================
396// Comparison
397// ============================
398
399impl Eq for Str {}
400impl PartialEq<Self> for Str {
401	fn eq(&self, other: &Self) -> bool {
402		self.0.ptr_eq(&other.0) || self.as_str() == other.as_str()
403	}
404}
405
406impl PartialEq<str> for Str {
407	#[inline(always)]
408	fn eq(&self, other: &str) -> bool {
409		self.as_str() == other
410	}
411}
412
413impl PartialEq<Str> for str {
414	#[inline(always)]
415	fn eq(&self, other: &Str) -> bool {
416		other == self
417	}
418}
419
420impl<'a> PartialEq<&'a str> for Str {
421	#[inline(always)]
422	fn eq(&self, other: &&'a str) -> bool {
423		self == *other
424	}
425}
426
427impl PartialEq<Str> for &str {
428	#[inline(always)]
429	fn eq(&self, other: &Str) -> bool {
430		*self == other
431	}
432}
433
434impl PartialEq<String> for Str {
435	#[inline(always)]
436	fn eq(&self, other: &String) -> bool {
437		self.as_str() == other
438	}
439}
440
441impl PartialEq<Str> for String {
442	#[inline(always)]
443	fn eq(&self, other: &Str) -> bool {
444		other == self
445	}
446}
447
448impl<'a> PartialEq<&'a String> for Str {
449	#[inline(always)]
450	fn eq(&self, other: &&'a String) -> bool {
451		self == *other
452	}
453}
454
455impl PartialEq<Str> for &String {
456	#[inline(always)]
457	fn eq(&self, other: &Str) -> bool {
458		*self == other
459	}
460}
461
462impl Ord for Str {
463	fn cmp(&self, other: &Self) -> Ordering {
464		self.as_str().cmp(other.as_str())
465	}
466}
467
468impl PartialOrd for Str {
469	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
470		Some(self.cmp(other))
471	}
472}
473
474impl PartialOrd<str> for Str {
475	#[inline(always)]
476	fn partial_cmp(&self, other: &str) -> Option<Ordering> {
477		self.as_str().partial_cmp(other)
478	}
479}
480
481impl PartialOrd<Str> for str {
482	#[inline(always)]
483	fn partial_cmp(&self, other: &Str) -> Option<Ordering> {
484		self.partial_cmp(other.as_str())
485	}
486}
487
488impl<'a> PartialOrd<&'a str> for Str {
489	#[inline(always)]
490	fn partial_cmp(&self, other: &&'a str) -> Option<Ordering> {
491		self.partial_cmp(*other)
492	}
493}
494
495impl PartialOrd<Str> for &str {
496	#[inline(always)]
497	fn partial_cmp(&self, other: &Str) -> Option<Ordering> {
498		(*self).partial_cmp(other)
499	}
500}
501
502impl hash::Hash for Str {
503	fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
504		self.as_str().hash(hasher);
505	}
506}
507
508// ============================
509// Formatting
510// ============================
511
512impl fmt::Debug for Str {
513	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
514		fmt::Debug::fmt(self.as_str(), f)
515	}
516}
517
518impl fmt::Display for Str {
519	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
520		fmt::Display::fmt(self.as_str(), f)
521	}
522}
523
524impl fmt::Debug for StrMut {
525	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
526		fmt::Debug::fmt(self.as_str(), f)
527	}
528}
529
530impl fmt::Display for StrMut {
531	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
532		fmt::Display::fmt(self.as_str(), f)
533	}
534}
535
536// ============================
537// StrMut Comparison
538// ============================
539
540impl Eq for StrMut {}
541impl PartialEq<Self> for StrMut {
542	fn eq(&self, other: &Self) -> bool {
543		self.0.ptr_eq(&other.0) || self.as_str() == other.as_str()
544	}
545}
546
547impl PartialEq<str> for StrMut {
548	#[inline(always)]
549	fn eq(&self, other: &str) -> bool {
550		self.as_str() == other
551	}
552}
553
554impl PartialEq<StrMut> for str {
555	#[inline(always)]
556	fn eq(&self, other: &StrMut) -> bool {
557		other == self
558	}
559}
560
561impl<'a> PartialEq<&'a str> for StrMut {
562	#[inline(always)]
563	fn eq(&self, other: &&'a str) -> bool {
564		self == *other
565	}
566}
567
568impl PartialEq<StrMut> for &str {
569	#[inline(always)]
570	fn eq(&self, other: &StrMut) -> bool {
571		*self == other
572	}
573}
574
575impl PartialEq<String> for StrMut {
576	#[inline(always)]
577	fn eq(&self, other: &String) -> bool {
578		self.as_str() == other
579	}
580}
581
582impl PartialEq<StrMut> for String {
583	#[inline(always)]
584	fn eq(&self, other: &StrMut) -> bool {
585		other == self
586	}
587}
588
589impl<'a> PartialEq<&'a String> for StrMut {
590	#[inline(always)]
591	fn eq(&self, other: &&'a String) -> bool {
592		self == *other
593	}
594}
595
596impl PartialEq<StrMut> for &String {
597	#[inline(always)]
598	fn eq(&self, other: &StrMut) -> bool {
599		*self == other
600	}
601}
602
603impl Ord for StrMut {
604	fn cmp(&self, other: &Self) -> Ordering {
605		self.as_str().cmp(other.as_str())
606	}
607}
608
609impl PartialOrd for StrMut {
610	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
611		Some(self.cmp(other))
612	}
613}
614
615impl PartialOrd<str> for StrMut {
616	#[inline(always)]
617	fn partial_cmp(&self, other: &str) -> Option<Ordering> {
618		self.as_str().partial_cmp(other)
619	}
620}
621
622impl PartialOrd<StrMut> for str {
623	#[inline(always)]
624	fn partial_cmp(&self, other: &StrMut) -> Option<Ordering> {
625		self.partial_cmp(other.as_str())
626	}
627}
628
629impl<'a> PartialOrd<&'a str> for StrMut {
630	#[inline(always)]
631	fn partial_cmp(&self, other: &&'a str) -> Option<Ordering> {
632		self.partial_cmp(*other)
633	}
634}
635
636impl PartialOrd<StrMut> for &str {
637	#[inline(always)]
638	fn partial_cmp(&self, other: &StrMut) -> Option<Ordering> {
639		(*self).partial_cmp(other)
640	}
641}
642
643impl hash::Hash for StrMut {
644	fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
645		self.as_str().hash(hasher);
646	}
647}
648
649// ============================
650// Borrows
651// ============================
652
653impl AsRef<str> for Str {
654	#[inline(always)]
655	fn as_ref(&self) -> &str {
656		self.as_str()
657	}
658}
659
660impl AsRef<[u8]> for Str {
661	#[inline(always)]
662	fn as_ref(&self) -> &[u8] {
663		self.as_str().as_bytes()
664	}
665}
666
667impl AsRef<std::ffi::OsStr> for Str {
668	#[inline(always)]
669	fn as_ref(&self) -> &std::ffi::OsStr {
670		AsRef::<std::ffi::OsStr>::as_ref(self.as_str())
671	}
672}
673
674impl AsRef<std::path::Path> for Str {
675	#[inline(always)]
676	fn as_ref(&self) -> &std::path::Path {
677		AsRef::<std::path::Path>::as_ref(self.as_str())
678	}
679}
680
681impl Borrow<str> for Str {
682	#[inline(always)]
683	fn borrow(&self) -> &str {
684		self.as_str()
685	}
686}
687
688impl Deref for Str {
689	type Target = str;
690
691	#[inline(always)]
692	fn deref(&self) -> &str {
693		self.as_str()
694	}
695}
696
697impl AsRef<str> for StrMut {
698	#[inline(always)]
699	fn as_ref(&self) -> &str {
700		self.as_str()
701	}
702}
703
704impl AsMut<str> for StrMut {
705	#[inline(always)]
706	fn as_mut(&mut self) -> &mut str {
707		self.as_str_mut()
708	}
709}
710
711impl AsRef<[u8]> for StrMut {
712	#[inline(always)]
713	fn as_ref(&self) -> &[u8] {
714		self.as_str().as_bytes()
715	}
716}
717
718impl AsRef<std::ffi::OsStr> for StrMut {
719	#[inline(always)]
720	fn as_ref(&self) -> &std::ffi::OsStr {
721		AsRef::<std::ffi::OsStr>::as_ref(self.as_str())
722	}
723}
724
725impl AsRef<std::path::Path> for StrMut {
726	#[inline(always)]
727	fn as_ref(&self) -> &std::path::Path {
728		AsRef::<std::path::Path>::as_ref(self.as_str())
729	}
730}
731
732impl Borrow<str> for StrMut {
733	#[inline(always)]
734	fn borrow(&self) -> &str {
735		self.as_str()
736	}
737}
738
739impl BorrowMut<str> for StrMut {
740	#[inline(always)]
741	fn borrow_mut(&mut self) -> &mut str {
742		self.as_str_mut()
743	}
744}
745
746impl Deref for StrMut {
747	type Target = str;
748
749	#[inline(always)]
750	fn deref(&self) -> &str {
751		self.as_str()
752	}
753}
754
755impl DerefMut for StrMut {
756	#[inline(always)]
757	fn deref_mut(&mut self) -> &mut str {
758		self.as_str_mut()
759	}
760}
761
762// ============================
763// Add implementations
764// ============================
765
766impl Add<&str> for Str {
767	type Output = Self;
768
769	#[inline]
770	fn add(self, rhs: &str) -> Self::Output {
771		match self.try_into_mut() {
772			Ok(mut lhs) => {
773				lhs.push_str(rhs);
774				lhs.freeze()
775			},
776			Err(this) => {
777				let mut lhs = StrMut::with_capacity(this.len() + rhs.len());
778				lhs.push_str(&this);
779				lhs.push_str(rhs);
780				lhs.freeze()
781			},
782		}
783	}
784}
785
786impl Add<Str> for &str {
787	type Output = Str;
788
789	#[inline]
790	fn add(self, rhs: Str) -> Self::Output {
791		match rhs.try_into_mut() {
792			Ok(mut rhs) => {
793				rhs.insert(0, self);
794				rhs.freeze()
795			},
796			Err(rhs) => {
797				let mut result = StrMut::with_capacity(self.len() + rhs.len());
798				result.push_str(self);
799				result.push_str(rhs.as_str());
800				result.freeze()
801			},
802		}
803	}
804}
805
806impl Add<&str> for &Str {
807	type Output = Str;
808
809	#[inline]
810	fn add(self, rhs: &str) -> Self::Output {
811		let mut result = StrMut::with_capacity(self.len() + rhs.len());
812		result.push_str(self);
813		result.push_str(rhs);
814		result.freeze()
815	}
816}
817
818impl Add<&Str> for &str {
819	type Output = Str;
820
821	#[inline]
822	fn add(self, rhs: &Str) -> Self::Output {
823		let mut result = StrMut::with_capacity(self.len() + rhs.len());
824		result.push_str(self);
825		result.push_str(rhs.as_str());
826		result.freeze()
827	}
828}
829
830impl Add<&str> for StrMut {
831	type Output = Self;
832
833	#[inline]
834	fn add(mut self, rhs: &str) -> Self::Output {
835		self.push_str(rhs);
836		self
837	}
838}
839
840impl Add<StrMut> for &str {
841	type Output = StrMut;
842
843	#[inline]
844	fn add(self, mut rhs: StrMut) -> Self::Output {
845		// Optimize by inserting at the beginning if we own the rhs
846		rhs.insert(0, self);
847		rhs
848	}
849}
850
851impl Add<&str> for &StrMut {
852	type Output = StrMut;
853
854	#[inline]
855	fn add(self, rhs: &str) -> Self::Output {
856		let mut result = StrMut::with_capacity(self.len() + rhs.len());
857		result.push_str(self.as_str());
858		result.push_str(rhs);
859		result
860	}
861}
862
863impl Add<&StrMut> for &str {
864	type Output = StrMut;
865
866	#[inline]
867	fn add(self, rhs: &StrMut) -> Self::Output {
868		let mut result = StrMut::with_capacity(self.len() + rhs.len());
869		result.push_str(self);
870		result.push_str(rhs.as_str());
871		result
872	}
873}
874
875// Str + Str combinations
876impl Add<Self> for Str {
877	type Output = Self;
878
879	#[inline]
880	fn add(self, rhs: Self) -> Self::Output {
881		match self.try_into_mut() {
882			Ok(mut lhs) => {
883				lhs.push_str(&rhs);
884				lhs.freeze()
885			},
886			Err(lhs) => match rhs.try_into_mut() {
887				Ok(mut rhs) => {
888					rhs.insert(0, &lhs);
889					rhs.freeze()
890				},
891				Err(rhs) => {
892					let mut result = StrMut::with_capacity(lhs.len() + rhs.len());
893					result.push_str(&lhs);
894					result.push_str(&rhs);
895					result.freeze()
896				},
897			},
898		}
899	}
900}
901
902impl Add<&Self> for Str {
903	type Output = Self;
904
905	#[inline]
906	fn add(self, rhs: &Self) -> Self::Output {
907		match self.try_into_mut() {
908			Ok(mut lhs) => {
909				lhs.push_str(rhs);
910				lhs.freeze()
911			},
912			Err(lhs) => {
913				let mut result = StrMut::with_capacity(lhs.len() + rhs.len());
914				result.push_str(&lhs);
915				result.push_str(rhs);
916				result.freeze()
917			},
918		}
919	}
920}
921
922impl Add<Str> for &Str {
923	type Output = Str;
924
925	#[inline]
926	fn add(self, rhs: Str) -> Self::Output {
927		match rhs.try_into_mut() {
928			Ok(mut rhs) => {
929				rhs.insert(0, self);
930				rhs.freeze()
931			},
932			Err(rhs) => {
933				let mut result = StrMut::with_capacity(self.len() + rhs.len());
934				result.push_str(self);
935				result.push_str(&rhs);
936				result.freeze()
937			},
938		}
939	}
940}
941
942impl Add<&Str> for &Str {
943	type Output = Str;
944
945	#[inline]
946	fn add(self, rhs: &Str) -> Self::Output {
947		let mut result = StrMut::with_capacity(self.len() + rhs.len());
948		result.push_str(self);
949		result.push_str(rhs);
950		result.freeze()
951	}
952}
953
954// StrMut + StrMut combinations
955impl Add<Self> for StrMut {
956	type Output = Self;
957
958	#[inline]
959	fn add(mut self, rhs: Self) -> Self::Output {
960		self.push_str(&rhs);
961		self
962	}
963}
964
965impl Add<&Self> for StrMut {
966	type Output = Self;
967
968	#[inline]
969	fn add(mut self, rhs: &Self) -> Self::Output {
970		self.push_str(rhs.as_str());
971		self
972	}
973}
974
975impl Add<StrMut> for &StrMut {
976	type Output = StrMut;
977
978	#[inline]
979	fn add(self, mut rhs: StrMut) -> Self::Output {
980		rhs.insert(0, self.as_str());
981		rhs
982	}
983}
984
985impl Add<&StrMut> for &StrMut {
986	type Output = StrMut;
987
988	#[inline]
989	fn add(self, rhs: &StrMut) -> Self::Output {
990		let mut result = StrMut::with_capacity(self.len() + rhs.len());
991		result.push_str(self.as_str());
992		result.push_str(rhs.as_str());
993		result
994	}
995}
996
997// ============================
998// Repr
999// ============================
1000
1001const INLINE_CAP: usize = 23;
1002
1003#[derive(Debug)]
1004enum Repr<H> {
1005	Inline(heapless::String<INLINE_CAP, u8>),
1006	Heap(H),
1007}
1008
1009impl<H: Clone> Clone for Repr<H> {
1010	#[inline]
1011	fn clone(&self) -> Self {
1012		match self {
1013			Self::Heap(data) => Self::Heap(data.clone()),
1014			// SAFETY: For Inline variant, we perform a bitwise copy using ptr::read.
1015			// This is safe because the Inline variant contains only Copy types
1016			// (heapless::String which is a wrapper around a fixed-size array).
1017			_ => unsafe { ptr::read(self as *const Self) },
1018		}
1019	}
1020}
1021
1022impl<H> Default for Repr<H> {
1023	#[inline]
1024	fn default() -> Self {
1025		Self::new()
1026	}
1027}
1028
1029impl<H> Repr<H> {
1030	#[inline(always)]
1031	const fn new() -> Self {
1032		Self::Inline(heapless::String::new())
1033	}
1034}
1035
1036impl<H> Repr<H>
1037where
1038	H: Deref<Target = str> + for<'a> From<&'a str>,
1039{
1040	/// This function tries to create a new `Repr::Inline` or `Repr::Static`
1041	/// If it isn't possible, this function returns None
1042	#[inline(always)]
1043	fn new_inline(text: &str) -> Option<Self> {
1044		heapless::String::try_from(text).ok().map(Self::Inline)
1045	}
1046
1047	#[inline(always)]
1048	fn copy_from_str(text: &str) -> Self {
1049		match heapless::String::try_from(text) {
1050			Ok(buf) => Self::Inline(buf),
1051			Err(_) => Self::Heap(text.into()),
1052		}
1053	}
1054
1055	#[inline(always)]
1056	fn len(&self) -> usize {
1057		match self {
1058			Self::Heap(data) => data.len(),
1059			Self::Inline(buf) => buf.len(),
1060		}
1061	}
1062
1063	#[inline(always)]
1064	fn is_empty(&self) -> bool {
1065		match self {
1066			Self::Heap(data) => data.is_empty(),
1067			Self::Inline(buf) => buf.is_empty(),
1068		}
1069	}
1070
1071	#[inline]
1072	fn as_str(&self) -> &str {
1073		match self {
1074			Self::Heap(data) => data,
1075			Self::Inline(buf) => buf.as_str(),
1076		}
1077	}
1078
1079	#[inline]
1080	fn ptr_eq(&self, other: &Self) -> bool {
1081		let (this, that) = (self.as_str(), other.as_str());
1082		// Pointer identity alone is not equality: zero-copy prefix slices
1083		// share their parent's start pointer with a different length.
1084		ptr::eq(this.as_ptr(), that.as_ptr()) && this.len() == that.len()
1085	}
1086}
1087
1088// ============================
1089// Extend / Format
1090// ============================
1091
1092/// Formats arguments to a [`Str`], potentially without allocating.
1093///
1094/// See [`std::format!`] or [`format_args!`] for syntax documentation.
1095#[macro_export]
1096macro_rules! fmts {
1097    ($($tt:tt)*) => {{
1098        let mut w = $crate::str::StrMut::default();
1099        ::std::fmt::Write::write_fmt(&mut w, format_args!($($tt)*))
1100         .expect("a formatting trait implementation returned an error");
1101        w.freeze()
1102    }};
1103}
1104
1105/// Formats arguments to a [`StrMut`], potentially without allocating.
1106///
1107/// See [`std::format!`] or [`format_args!`] for syntax documentation.
1108#[macro_export]
1109macro_rules! fmts_mut {
1110    ($($tt:tt)*) => {{
1111        let mut w = $crate::str::StrMut::default();
1112        ::std::fmt::Write::write_fmt(&mut w, format_args!($($tt)*))
1113         .expect("a formatting trait implementation returned an error");
1114        w
1115    }};
1116}
1117
1118macro_rules! impl_extend {
1119    // Case with explicit lifetime
1120    (for<$lt:lifetime> $type:ty, ($this:ident, $item:ident) => $($body:tt)*) => {
1121        impl<$lt> Extend<$type> for StrMut {
1122            fn extend<T: IntoIterator<Item = $type>>(&mut self, iter: T) {
1123                let $this: &mut StrMut = self;
1124                for $item in iter {
1125                    $($body)*
1126                }
1127            }
1128        }
1129        impl<$lt> FromIterator<$type> for StrMut {
1130            fn from_iter<T: IntoIterator<Item = $type>>(iter: T) -> Self {
1131                let mut $this = StrMut::default();
1132                $this.extend(iter);
1133                $this
1134            }
1135        }
1136        impl<$lt> FromIterator<$type> for Str {
1137            fn from_iter<T: IntoIterator<Item = $type>>(iter: T) -> Self {
1138                let mut $this = StrMut::default();
1139                $this.extend(iter);
1140                $this.freeze()
1141            }
1142        }
1143    };
1144    // Case without lifetimes
1145    ($type:ty, ($this:ident, $item:ident) => $($body:tt)*) => {
1146        impl Extend<$type> for StrMut {
1147            fn extend<T: IntoIterator<Item = $type>>(&mut self, iter: T) {
1148                let $this: &mut StrMut = self;
1149                for $item in iter {
1150                    $($body)*
1151                }
1152            }
1153        }
1154        impl FromIterator<$type> for StrMut {
1155            fn from_iter<T: IntoIterator<Item = $type>>(iter: T) -> Self {
1156                let mut $this = StrMut::default();
1157                $this.extend(iter);
1158                $this
1159            }
1160        }
1161        impl FromIterator<$type> for Str {
1162            fn from_iter<T: IntoIterator<Item = $type>>(iter: T) -> Self {
1163                let mut $this = StrMut::default();
1164                $this.extend(iter);
1165                $this.freeze()
1166            }
1167        }
1168    };
1169}
1170
1171impl_extend!(char, (s, rhs) => s.push(rhs));
1172impl_extend!(String, (s, rhs) => s.push_str(rhs.as_str()));
1173impl_extend!(for<'a> &'a String, (s, rhs) => s.push_str(rhs.as_str()));
1174impl_extend!(for<'a> &'a str, (s, rhs) => s.push_str(rhs));
1175
1176// ============================
1177// StrMut
1178// ============================
1179
1180/// Mutable, growable counterpart of [`Str`]: same inline layout for
1181/// strings up to 23 bytes, heap-backed above.
1182///
1183/// Build with `push`/`push_str` (or
1184/// [`fmts_mut!`](crate::fmts_mut)), then [`freeze`](Self::freeze)
1185/// into an immutable [`Str`] without copying.
1186#[derive(Default, Clone)]
1187#[repr(transparent)]
1188pub struct StrMut(Repr<BytesStrMut>);
1189
1190impl StrMut {
1191	/// Constructs a `StrMut` from a `BytesMut` object without checking for
1192	/// UTF-8 validity.
1193	///
1194	/// # Safety
1195	///
1196	/// The caller must ensure that the bytes are valid UTF-8. If this condition
1197	/// is not met, the behavior is undefined.
1198	#[inline]
1199	pub unsafe fn from_utf8_unchecked_owned(u: impl Into<BytesMut>) -> Self {
1200		// SAFETY: The caller guarantees that the bytes are valid UTF-8.
1201		Self(Repr::Heap(unsafe { BytesStrMut::from_inner_unchecked(u.into()) }))
1202	}
1203
1204	/// Constructs a `StrMut` from a byte slice without checking for UTF-8
1205	/// validity.
1206	///
1207	/// # Safety
1208	///
1209	/// The caller must ensure that the bytes are valid UTF-8. If this condition
1210	/// is not met, the behavior is undefined.
1211	#[inline]
1212	pub unsafe fn from_utf8_unchecked(u: &[u8]) -> Self {
1213		// SAFETY: The caller guarantees that the bytes are valid UTF-8.
1214		Self::new(unsafe { str::from_utf8_unchecked(u) })
1215	}
1216
1217	/// Constructs a `StrMut` from a `BytesMut` object, checking for UTF-8
1218	/// validity.
1219	///
1220	/// Returns an error if the bytes are not valid UTF-8.
1221	#[inline]
1222	pub fn from_utf8_owned(u: impl Into<BytesMut>) -> Result<Self, Utf8ErrorMut> {
1223		let u: BytesMut = u.into();
1224		Ok(Self(Repr::Heap(BytesStrMut::from_inner(u)?)))
1225	}
1226
1227	/// Constructs a `StrMut` from a byte slice, checking for UTF-8 validity.
1228	///
1229	/// Returns an error if the bytes are not valid UTF-8.
1230	#[inline]
1231	pub fn from_utf8(u: &[u8]) -> Result<Self, str::Utf8Error> {
1232		Ok(Self::new(str::from_utf8(u)?))
1233	}
1234
1235	/// Constructs an inline variant of `StrMut`.
1236	///
1237	/// This never allocates.
1238	///
1239	/// # Panics
1240	///
1241	/// Panics if `text.len() > 23`.
1242	#[inline]
1243	pub fn new_inline(text: &str) -> Self {
1244		Self(Repr::new_inline(text).expect("len <= INLINE_CAP"))
1245	}
1246
1247	/// Constructs a `Str` from a `str`, heap-allocating if necessary.
1248	#[inline(always)]
1249	pub fn new(text: impl AsRef<str>) -> Self {
1250		Self(Repr::copy_from_str(text.as_ref()))
1251	}
1252
1253	/// Constructs a `StrMut` with the given capacity.
1254	#[inline]
1255	pub fn with_capacity(capacity: usize) -> Self {
1256		if capacity > INLINE_CAP {
1257			// SAFETY: A newly allocated BytesMut with capacity is empty, and an
1258			// empty byte buffer is trivially valid UTF-8.
1259			Self(Repr::Heap(unsafe {
1260				BytesStrMut::from_inner_unchecked(BytesMut::with_capacity(capacity))
1261			}))
1262		} else {
1263			Self(Repr::new())
1264		}
1265	}
1266
1267	/// Returns a `&str` slice of this `Str`.
1268	#[inline(always)]
1269	pub fn as_str(&self) -> &str {
1270		self.0.as_str()
1271	}
1272
1273	/// Returns a mutable `&str` slice of this `Str`.
1274	#[inline(always)]
1275	pub fn as_str_mut(&mut self) -> &mut str {
1276		match &mut self.0 {
1277			// SAFETY: BytesStrMut guarantees that its inner BytesMut contains valid UTF-8.
1278			Repr::Heap(data) => unsafe { str::from_utf8_unchecked_mut(data.as_bytes_mut()) },
1279			Repr::Inline(buf) => buf.as_mut_str(),
1280		}
1281	}
1282
1283	/// Returns the length of `self` in bytes.
1284	#[inline(always)]
1285	pub fn len(&self) -> usize {
1286		self.0.len()
1287	}
1288
1289	/// Returns `true` if `self` has a length of zero bytes.
1290	#[inline(always)]
1291	pub fn is_empty(&self) -> bool {
1292		self.0.is_empty()
1293	}
1294
1295	/// Truncates the `Str` to the specified length.
1296	///
1297	/// If `len` is greater than the current length, this has no effect.
1298	///
1299	/// # Panics
1300	///
1301	/// Panics if `len` is greater than the current length of the `Str` or if
1302	/// `len` is not on a valid UTF-8 character boundary.
1303	#[inline]
1304	pub fn truncate(&mut self, len: usize) {
1305		match &mut self.0 {
1306			Repr::Inline(buf) => {
1307				buf.truncate(len);
1308			},
1309			Repr::Heap(heap) => {
1310				assert!(heap.is_char_boundary(len), "Index is not on a char boundary");
1311				// SAFETY: Truncating at a char boundary (verified by the assert above)
1312				// preserves UTF-8 validity of the underlying byte buffer.
1313				unsafe {
1314					heap.inner_mut().truncate(len);
1315				}
1316			},
1317		}
1318	}
1319
1320	/// Returns `true` if `self` is heap-allocated.
1321	#[inline(always)]
1322	pub const fn is_spilled(&self) -> bool {
1323		matches!(self.0, Repr::Heap(..))
1324	}
1325
1326	/// Reserves capacity for at least `additional` more bytes to be inserted in
1327	/// the given `StrMut`.
1328	#[inline]
1329	pub fn reserve(&mut self, additional: usize) {
1330		match &mut self.0 {
1331			Repr::Inline(buf) => {
1332				let cap = buf.len() + additional;
1333				if cap > INLINE_CAP {
1334					let cap = cap.next_power_of_two();
1335					// SAFETY: A newly allocated BytesMut with capacity is empty, and an
1336					// empty byte buffer is trivially valid UTF-8.
1337					let mut heap =
1338						unsafe { BytesStrMut::from_inner_unchecked(BytesMut::with_capacity(cap)) };
1339					heap.push_str(buf.as_str());
1340					*self = Self(Repr::Heap(heap));
1341				}
1342			},
1343			Repr::Heap(heap) => {
1344				// SAFETY: Reserving capacity does not modify the existing UTF-8 bytes,
1345				// only extends the available capacity.
1346				unsafe {
1347					heap.inner_mut().reserve(additional);
1348				}
1349			},
1350		}
1351	}
1352
1353	/// Builds a [`Str`] from `self`.
1354	#[must_use]
1355	#[inline]
1356	pub fn freeze(self) -> Str {
1357		Str(match self.0 {
1358			Repr::Inline(buf) => Repr::Inline(buf),
1359			Repr::Heap(heap) => Repr::Heap(heap.freeze()),
1360		})
1361	}
1362
1363	/// Appends the given [`char`] to the end of `self`'s buffer.
1364	#[inline]
1365	pub fn push(&mut self, c: char) {
1366		let mut buf = [0; 4];
1367		self.push_str(c.encode_utf8(&mut buf));
1368	}
1369
1370	/// Appends a given string slice onto the end of `self`'s buffer.
1371	#[inline]
1372	pub fn push_str(&mut self, s: &str) {
1373		match &mut self.0 {
1374			Repr::Inline(buf) => {
1375				let len = buf.len();
1376				if buf.push_str(s).is_err() {
1377					let mut heap = BytesMut::with_capacity((len + s.len()).next_power_of_two());
1378					heap.extend_from_slice(buf.as_bytes());
1379					heap.extend_from_slice(s.as_bytes());
1380					// SAFETY: We copy valid UTF-8 bytes from buf and s into heap.
1381					// Both sources are valid UTF-8, so the result is valid UTF-8.
1382					*self = Self(Repr::Heap(unsafe { BytesStrMut::from_inner_unchecked(heap) }));
1383				}
1384			},
1385			Repr::Heap(heap) => heap.push_str(s),
1386		}
1387	}
1388
1389	/// Pushes raw bytes onto the end of `self`'s buffer.
1390	///
1391	/// # Safety
1392	///
1393	/// The caller must ensure that the bytes are valid UTF-8. If this condition
1394	/// is not met, the behavior is undefined.
1395	#[inline]
1396	pub unsafe fn extend_from_bytes_unchecked(&mut self, s: &[u8]) {
1397		match &mut self.0 {
1398			Repr::Inline(buf) => {
1399				let len = buf.len();
1400				// SAFETY: The caller guarantees that s contains valid UTF-8 bytes.
1401				// We extend the inline buffer's internal vector directly.
1402				if unsafe { buf.as_mut_vec().extend_from_slice(s).is_err() } {
1403					let mut heap = BytesMut::with_capacity((len + s.len()).next_power_of_two());
1404					heap.extend_from_slice(buf.as_bytes());
1405					heap.extend_from_slice(s);
1406					// SAFETY: buf contains valid UTF-8 and the caller guarantees s
1407					// contains valid UTF-8, so heap contains valid UTF-8.
1408					*self = Self(Repr::Heap(unsafe { BytesStrMut::from_inner_unchecked(heap) }));
1409				}
1410			},
1411			// SAFETY: The caller guarantees that s contains valid UTF-8 bytes.
1412			Repr::Heap(heap) => unsafe { heap.inner_mut().push_slice(s) },
1413		}
1414	}
1415
1416	/// Inserts a given string slice at the specified position in `self`'s
1417	/// buffer.
1418	///
1419	/// # Panics
1420	///
1421	/// Panics if `index` is greater than the current length of the string or if
1422	/// it is not on a valid UTF-8 character boundary.
1423	#[inline]
1424	pub fn insert(&mut self, index: usize, s: &str) {
1425		match &mut self.0 {
1426			Repr::Inline(buf) => {
1427				// First check if index is on a valid char boundary
1428				assert!(
1429					buf.is_char_boundary(index),
1430					"index is not on a valid UTF-8 character boundary"
1431				);
1432
1433				if buf.insert_str(index, s).is_err() {
1434					// Inline buffer doesn't have enough capacity, promote to heap
1435					let old_len = buf.len();
1436					let new_len = old_len + s.len();
1437					let mut heap = BytesMut::with_capacity(new_len.next_power_of_two());
1438
1439					// Copy the part before the insertion point
1440					heap.extend_from_slice(&buf.as_bytes()[..index]);
1441					// Insert the new string
1442					heap.extend_from_slice(s.as_bytes());
1443					// Copy the part after the insertion point
1444					heap.extend_from_slice(&buf.as_bytes()[index..]);
1445
1446					// SAFETY: We copy valid UTF-8 bytes from buf (before and after index)
1447					// and valid UTF-8 bytes from s. The result is valid UTF-8 because we
1448					// insert at a valid char boundary (verified by the assert above).
1449					*self = Self(Repr::Heap(unsafe { BytesStrMut::from_inner_unchecked(heap) }));
1450				}
1451			},
1452			Repr::Heap(heap) => {
1453				assert!(
1454					heap.is_char_boundary(index),
1455					"index is not on a valid UTF-8 character boundary"
1456				);
1457				// SAFETY: We have mutable access to the StrMut, so we can get
1458				// mutable access to the inner BytesMut.
1459				let inner = unsafe { heap.inner_mut() };
1460
1461				let len = inner.len();
1462				let string_len = s.len();
1463				inner.reserve(string_len);
1464
1465				// SAFETY: Move the bytes starting from `index` to their new location
1466				// `string_len` bytes ahead. This is safe because we checked there is
1467				// sufficient capacity, and `index` is a char boundary.
1468				unsafe {
1469					let ptr = inner.as_mut_ptr();
1470					core::ptr::copy(ptr.add(index), ptr.add(index + string_len), len - index);
1471				}
1472
1473				// SAFETY: Copy the new string slice into the vacated region if
1474				// `index != len`, or into the uninitialized spare capacity otherwise.
1475				// The source (s) and destination do not overlap because s is an
1476				// independent string slice.
1477				unsafe {
1478					core::ptr::copy_nonoverlapping(
1479						s.as_ptr(),
1480						inner.as_mut_ptr().add(index),
1481						string_len,
1482					);
1483				}
1484
1485				// SAFETY: We've just initialized `string_len` bytes at position
1486				// `index`, and moved the existing bytes to make room. The total
1487				// length is now len + string_len. The resulting bytes are valid
1488				// UTF-8 because we inserted at a char boundary and s is valid UTF-8.
1489				unsafe {
1490					inner.set_len(len + string_len);
1491				}
1492			},
1493		}
1494	}
1495}
1496
1497impl fmt::Write for StrMut {
1498	#[inline]
1499	fn write_str(&mut self, s: &str) -> fmt::Result {
1500		self.push_str(s);
1501		Ok(())
1502	}
1503}
1504
1505// ============================
1506// IntoStr
1507// ============================
1508
1509/// Convert value to [`Str`]/[`StrMut`] using [`fmt::Display`],
1510/// potentially without allocating.
1511///
1512/// Almost identical to [`ToString`], but converts to [`Str`]/[`StrMut`]
1513/// instead.
1514pub trait IntoStr: fmt::Display {
1515	/// Convert value to [`Str`].
1516	fn into_str(self) -> Str
1517	where
1518		Self: Sized,
1519	{
1520		self.to_str()
1521	}
1522
1523	/// Convert value to [`StrMut`].
1524	fn into_str_mut(self) -> StrMut
1525	where
1526		Self: Sized,
1527	{
1528		self.into_str().into()
1529	}
1530
1531	/// Convert value to [`Str`].
1532	fn to_str(&self) -> Str {
1533		fmts!("{self}")
1534	}
1535
1536	/// Convert value to [`StrMut`].
1537	fn to_strmut(&self) -> StrMut {
1538		self.to_str().into()
1539	}
1540}
1541
1542impl IntoStr for &str {
1543	#[inline]
1544	fn into_str(self) -> Str {
1545		Str::new(self)
1546	}
1547
1548	#[inline]
1549	fn into_str_mut(self) -> StrMut {
1550		StrMut::new(self)
1551	}
1552
1553	#[inline]
1554	fn to_str(&self) -> Str {
1555		Str::new(self)
1556	}
1557
1558	#[inline]
1559	fn to_strmut(&self) -> StrMut {
1560		StrMut::new(self)
1561	}
1562}
1563
1564impl IntoStr for &mut str {
1565	#[inline]
1566	fn into_str(self) -> Str {
1567		Str::new(self)
1568	}
1569
1570	#[inline]
1571	fn into_str_mut(self) -> StrMut {
1572		StrMut::new(self)
1573	}
1574
1575	#[inline]
1576	fn to_str(&self) -> Str {
1577		Str::new(self)
1578	}
1579
1580	#[inline]
1581	fn to_strmut(&self) -> StrMut {
1582		StrMut::new(self)
1583	}
1584}
1585
1586impl IntoStr for Str {
1587	#[inline]
1588	fn into_str(self) -> Str {
1589		self
1590	}
1591
1592	#[inline]
1593	fn into_str_mut(self) -> StrMut {
1594		self.into()
1595	}
1596
1597	#[inline]
1598	fn to_str(&self) -> Str {
1599		self.clone()
1600	}
1601
1602	#[inline]
1603	fn to_strmut(&self) -> StrMut {
1604		StrMut::new(self.as_str())
1605	}
1606}
1607
1608impl IntoStr for StrMut {
1609	#[inline]
1610	fn into_str(self) -> Str {
1611		self.freeze()
1612	}
1613
1614	#[inline]
1615	fn into_str_mut(self) -> StrMut {
1616		self
1617	}
1618
1619	#[inline]
1620	fn to_str(&self) -> Str {
1621		Str::new(self.as_str())
1622	}
1623
1624	#[inline]
1625	fn to_strmut(&self) -> StrMut {
1626		self.clone()
1627	}
1628}
1629
1630impl IntoStr for CowStr<'_> {
1631	#[inline]
1632	fn into_str(self) -> Str {
1633		match self {
1634			CowStr::Borrowed(s) => Str::new(s),
1635			CowStr::Owned(s) => s.freeze(),
1636		}
1637	}
1638
1639	#[inline]
1640	fn into_str_mut(self) -> StrMut {
1641		match self {
1642			CowStr::Borrowed(s) => StrMut::new(s),
1643			CowStr::Owned(s) => s,
1644		}
1645	}
1646
1647	#[inline]
1648	fn to_str(&self) -> Str {
1649		Str::new(self.as_str())
1650	}
1651
1652	#[inline]
1653	fn to_strmut(&self) -> StrMut {
1654		StrMut::new(self.as_str())
1655	}
1656}
1657
1658impl IntoStr for String {
1659	#[inline]
1660	fn into_str(self) -> Str {
1661		Str(Repr::Heap(self.into()))
1662	}
1663
1664	#[inline]
1665	fn into_str_mut(self) -> StrMut {
1666		// SAFETY: String guarantees its contents are valid UTF-8. We convert
1667		// into bytes and then wrap in BytesStrMut, preserving UTF-8 validity.
1668		StrMut(Repr::Heap(unsafe {
1669			BytesStrMut::from_inner_unchecked(Bytes::from(self.into_bytes()).into())
1670		}))
1671	}
1672
1673	#[inline]
1674	fn to_str(&self) -> Str {
1675		self.as_str().into()
1676	}
1677
1678	#[inline]
1679	fn to_strmut(&self) -> StrMut {
1680		self.as_str().into()
1681	}
1682}
1683
1684impl IntoStr for BytesStr {
1685	#[inline]
1686	fn into_str(self) -> Str {
1687		Str(Repr::Heap(self))
1688	}
1689
1690	#[inline]
1691	fn into_str_mut(self) -> StrMut {
1692		// SAFETY: BytesStr guarantees its contents are valid UTF-8. Converting
1693		// to BytesMut preserves the UTF-8 bytes.
1694		StrMut(Repr::Heap(unsafe { BytesStrMut::from_inner_unchecked(self.into_inner().into()) }))
1695	}
1696
1697	#[inline]
1698	fn to_str(&self) -> Str {
1699		Str(Repr::Heap(self.clone()))
1700	}
1701
1702	#[inline]
1703	fn to_strmut(&self) -> StrMut {
1704		self.deref().into()
1705	}
1706}
1707
1708impl IntoStr for Cow<'_, str> {
1709	#[inline]
1710	fn into_str(self) -> Str {
1711		match self {
1712			Cow::Borrowed(s) => Str::new(s),
1713			Cow::Owned(s) => Str(Repr::Heap(s.into())),
1714		}
1715	}
1716
1717	#[inline]
1718	fn into_str_mut(self) -> StrMut {
1719		match self {
1720			Cow::Borrowed(s) => StrMut::new(s),
1721			Cow::Owned(s) => s.into_str_mut(),
1722		}
1723	}
1724
1725	#[inline]
1726	fn to_str(&self) -> Str {
1727		match self {
1728			Cow::Borrowed(s) => Str::new(s),
1729			Cow::Owned(s) => s.into_str(),
1730		}
1731	}
1732
1733	#[inline]
1734	fn to_strmut(&self) -> StrMut {
1735		match self {
1736			Cow::Borrowed(s) => StrMut::new(s),
1737			Cow::Owned(s) => s.into_str_mut(),
1738		}
1739	}
1740}
1741
1742impl IntoStr for Box<str> {
1743	#[inline]
1744	fn into_str(self) -> Str {
1745		Str(Repr::Heap(self.into()))
1746	}
1747
1748	#[inline]
1749	fn into_str_mut(self) -> StrMut {
1750		// SAFETY: Box<str> guarantees its contents are valid UTF-8. Converting
1751		// to boxed bytes and then to BytesMut preserves the UTF-8 bytes.
1752		StrMut(Repr::Heap(unsafe {
1753			BytesStrMut::from_inner_unchecked(Bytes::from(self.into_boxed_bytes()).into())
1754		}))
1755	}
1756
1757	#[inline]
1758	fn to_str(&self) -> Str {
1759		Str::new(self.as_ref())
1760	}
1761
1762	#[inline]
1763	fn to_strmut(&self) -> StrMut {
1764		StrMut::new(self.as_ref())
1765	}
1766}
1767
1768impl IntoStr for Arc<str> {
1769	#[inline]
1770	fn into_str(self) -> Str {
1771		let bytes: Arc<[u8]> = self.into();
1772		// SAFETY: Arc<str> guarantees its contents are valid UTF-8. Converting
1773		// to Arc<[u8]> preserves the bytes without modification.
1774		Str(Repr::Heap(unsafe { BytesStr::from_inner_unchecked(Bytes::from_owner(bytes)) }))
1775	}
1776
1777	#[inline]
1778	fn into_str_mut(self) -> StrMut {
1779		StrMut::new(self.as_ref())
1780	}
1781
1782	#[inline]
1783	fn to_str(&self) -> Str {
1784		Str::new(self.as_ref())
1785	}
1786
1787	#[inline]
1788	fn to_strmut(&self) -> StrMut {
1789		StrMut::new(self.as_ref())
1790	}
1791}
1792
1793impl<T> IntoStr for &T
1794where
1795	T: fmt::Display + ?Sized,
1796{
1797	default fn into_str(self) -> Str {
1798		fmts!("{}", self)
1799	}
1800
1801	#[inline]
1802	default fn into_str_mut(self) -> StrMut {
1803		fmts_mut!("{}", self)
1804	}
1805
1806	#[inline]
1807	default fn to_str(&self) -> Str {
1808		fmts!("{}", *self)
1809	}
1810
1811	#[inline]
1812	default fn to_strmut(&self) -> StrMut {
1813		fmts_mut!("{}", *self)
1814	}
1815}
1816
1817// ============================
1818// From
1819// ============================
1820
1821impl str::FromStr for Str {
1822	type Err = Infallible;
1823
1824	#[inline]
1825	fn from_str(s: &str) -> Result<Self, Self::Err> {
1826		Ok(Self::from(s))
1827	}
1828}
1829
1830impl From<fmt::Arguments<'_>> for Str {
1831	#[inline]
1832	fn from(args: fmt::Arguments<'_>) -> Self {
1833		args.into_str()
1834	}
1835}
1836
1837impl From<&str> for Str {
1838	#[inline]
1839	fn from(s: &str) -> Self {
1840		Self::new(s)
1841	}
1842}
1843
1844impl From<&mut str> for Str {
1845	#[inline]
1846	fn from(s: &mut str) -> Self {
1847		Self::new(s)
1848	}
1849}
1850
1851impl From<&str> for StrMut {
1852	#[inline]
1853	fn from(s: &str) -> Self {
1854		Self::new(s)
1855	}
1856}
1857
1858impl From<&mut str> for StrMut {
1859	#[inline]
1860	fn from(s: &mut str) -> Self {
1861		Self::new(s)
1862	}
1863}
1864
1865impl From<&String> for Str {
1866	#[inline]
1867	fn from(s: &String) -> Self {
1868		Self::new(s)
1869	}
1870}
1871
1872impl From<&String> for StrMut {
1873	#[inline]
1874	fn from(s: &String) -> Self {
1875		Self::new(s)
1876	}
1877}
1878
1879impl From<String> for Str {
1880	#[inline(always)]
1881	fn from(text: String) -> Self {
1882		Self(Repr::Heap(text.into()))
1883	}
1884}
1885
1886impl From<String> for StrMut {
1887	#[inline(always)]
1888	fn from(text: String) -> Self {
1889		// SAFETY: String guarantees its contents are valid UTF-8. Converting
1890		// into bytes preserves those UTF-8 bytes.
1891		Self(Repr::Heap(unsafe {
1892			BytesStrMut::from_inner_unchecked(Bytes::from(text.into_bytes()).into())
1893		}))
1894	}
1895}
1896
1897impl From<&BytesStr> for Str {
1898	#[inline]
1899	fn from(s: &BytesStr) -> Self {
1900		Self(Repr::Heap(s.clone()))
1901	}
1902}
1903
1904impl From<&BytesStr> for StrMut {
1905	#[inline]
1906	fn from(s: &BytesStr) -> Self {
1907		Self::new(&**s)
1908	}
1909}
1910
1911impl From<BytesStr> for Str {
1912	#[inline(always)]
1913	fn from(text: BytesStr) -> Self {
1914		Self(Repr::Heap(text))
1915	}
1916}
1917
1918impl From<BytesStr> for StrMut {
1919	#[inline(always)]
1920	fn from(text: BytesStr) -> Self {
1921		// SAFETY: BytesStr guarantees its contents are valid UTF-8. Converting
1922		// to BytesMut preserves the UTF-8 bytes.
1923		Self(Repr::Heap(unsafe {
1924			BytesStrMut::from_inner_unchecked(BytesMut::from(text.into_inner()))
1925		}))
1926	}
1927}
1928
1929impl From<BytesStrMut> for Str {
1930	#[inline]
1931	fn from(value: BytesStrMut) -> Self {
1932		Self(Repr::Heap(value.freeze()))
1933	}
1934}
1935
1936impl From<BytesStrMut> for StrMut {
1937	#[inline]
1938	fn from(value: BytesStrMut) -> Self {
1939		Self(Repr::Heap(value))
1940	}
1941}
1942
1943impl<'a> From<Cow<'a, str>> for Str {
1944	#[inline]
1945	fn from(s: Cow<'a, str>) -> Self {
1946		match s {
1947			Cow::Borrowed(borrowed) => Self::new(borrowed),
1948			Cow::Owned(owned) => Self(Repr::Heap(owned.into())),
1949		}
1950	}
1951}
1952
1953impl<'a> From<Cow<'a, str>> for StrMut {
1954	#[inline]
1955	fn from(s: Cow<'a, str>) -> Self {
1956		match s {
1957			Cow::Borrowed(borrowed) => borrowed.into(),
1958			Cow::Owned(owned) => owned.into(),
1959		}
1960	}
1961}
1962
1963impl From<Str> for BytesStr {
1964	#[inline(always)]
1965	fn from(text: Str) -> Self {
1966		match text.0 {
1967			Repr::Heap(data) => data,
1968			_ => text.as_str().into(),
1969		}
1970	}
1971}
1972
1973impl From<StrMut> for BytesStr {
1974	#[inline(always)]
1975	fn from(text: StrMut) -> Self {
1976		match text.0 {
1977			Repr::Heap(data) => data.freeze(),
1978			_ => text.as_str().into(),
1979		}
1980	}
1981}
1982
1983impl From<Str> for String {
1984	#[inline(always)]
1985	fn from(text: Str) -> Self {
1986		text.as_str().into()
1987	}
1988}
1989
1990impl From<StrMut> for String {
1991	#[inline(always)]
1992	fn from(text: StrMut) -> Self {
1993		text.as_str().into()
1994	}
1995}
1996
1997impl From<Str> for Bytes {
1998	#[inline(always)]
1999	fn from(text: Str) -> Self {
2000		match text.0 {
2001			Repr::Heap(data) => data.into(),
2002			Repr::Inline(buf) => Self::copy_from_slice(buf.as_bytes()),
2003		}
2004	}
2005}
2006
2007impl From<StrMut> for Bytes {
2008	#[inline(always)]
2009	fn from(text: StrMut) -> Self {
2010		match text.0 {
2011			Repr::Heap(data) => data.into_inner().into(),
2012			Repr::Inline(buf) => Self::copy_from_slice(buf.as_bytes()),
2013		}
2014	}
2015}
2016
2017impl From<Str> for BytesMut {
2018	#[inline(always)]
2019	fn from(value: Str) -> Self {
2020		match value.0 {
2021			Repr::Heap(data) => data.into_inner().into(),
2022			Repr::Inline(buf) => Self::from(buf.as_bytes()),
2023		}
2024	}
2025}
2026
2027impl From<StrMut> for BytesMut {
2028	#[inline(always)]
2029	fn from(text: StrMut) -> Self {
2030		match text.0 {
2031			Repr::Heap(data) => data.into_inner(),
2032			Repr::Inline(buf) => Self::from(buf.as_bytes()),
2033		}
2034	}
2035}
2036
2037impl From<Str> for BytesStrMut {
2038	#[inline(always)]
2039	fn from(value: Str) -> Self {
2040		// SAFETY: Str is guaranteed to contain valid UTF-8, so converting it to
2041		// BytesMut and then to BytesStrMut preserves UTF-8 validity.
2042		unsafe { Self::from_inner_unchecked(BytesMut::from(value)) }
2043	}
2044}
2045
2046impl From<StrMut> for BytesStrMut {
2047	#[inline(always)]
2048	fn from(value: StrMut) -> Self {
2049		match value.0 {
2050			Repr::Heap(data) => data,
2051			// SAFETY: buf contains valid UTF-8 (guaranteed by StrMut invariants).
2052			// Converting to BytesMut preserves the UTF-8 bytes.
2053			Repr::Inline(buf) => unsafe { Self::from_inner_unchecked(BytesMut::from(buf.as_bytes())) },
2054		}
2055	}
2056}
2057
2058impl From<StrMut> for Str {
2059	#[inline]
2060	fn from(value: StrMut) -> Self {
2061		value.freeze()
2062	}
2063}
2064
2065impl From<Str> for StrMut {
2066	#[inline]
2067	fn from(value: Str) -> Self {
2068		match value.0 {
2069			Repr::Inline(buf) => Self(Repr::Inline(buf)),
2070			// SAFETY: heap contains valid UTF-8 (guaranteed by Str invariants).
2071			Repr::Heap(heap) => unsafe { Self::from_utf8_unchecked_owned(heap.into_inner()) },
2072		}
2073	}
2074}
2075
2076impl From<Arc<str>> for Str {
2077	#[inline]
2078	fn from(value: Arc<str>) -> Self {
2079		let bytes: Arc<[u8]> = value.into();
2080		// SAFETY: Arc<str> guarantees its contents are valid UTF-8. Converting
2081		// to Arc<[u8]> preserves the bytes without modification.
2082		Self(Repr::Heap(unsafe { BytesStr::from_inner_unchecked(Bytes::from_owner(bytes)) }))
2083	}
2084}
2085
2086impl From<Box<str>> for Str {
2087	#[inline]
2088	fn from(value: Box<str>) -> Self {
2089		Self(Repr::Heap(value.into()))
2090	}
2091}
2092
2093impl From<Box<str>> for StrMut {
2094	#[inline]
2095	fn from(value: Box<str>) -> Self {
2096		// SAFETY: Box<str> guarantees its contents are valid UTF-8. Converting
2097		// to boxed bytes and then to BytesMut preserves the UTF-8 bytes.
2098		Self(Repr::Heap(unsafe {
2099			BytesStrMut::from_inner_unchecked(Bytes::from(value.into_boxed_bytes()).into())
2100		}))
2101	}
2102}
2103
2104// ============================
2105// Serde
2106// ============================
2107
2108impl serde::Serialize for Str {
2109	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2110	where
2111		S: serde::Serializer,
2112	{
2113		self.as_str().serialize(serializer)
2114	}
2115}
2116
2117impl<'de> serde::Deserialize<'de> for Str {
2118	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2119	where
2120		D: serde::Deserializer<'de>,
2121	{
2122		use serde::de::{Error, Unexpected};
2123		struct StrVisitor;
2124
2125		impl serde::de::Visitor<'_> for StrVisitor {
2126			type Value = Str;
2127
2128			fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2129				formatter.write_str("a string")
2130			}
2131
2132			fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
2133				Ok(Str::from(v))
2134			}
2135
2136			fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
2137				Ok(Str::from(v))
2138			}
2139
2140			fn visit_bytes<E: Error>(self, v: &[u8]) -> Result<Self::Value, E> {
2141				match str::from_utf8(v) {
2142					Ok(s) => Ok(Str::from(s)),
2143					Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)),
2144				}
2145			}
2146
2147			fn visit_byte_buf<E: Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
2148				match String::from_utf8(v) {
2149					Ok(s) => Ok(Str::from(s)),
2150					Err(e) => Err(Error::invalid_value(Unexpected::Bytes(&e.into_bytes()), &self)),
2151				}
2152			}
2153		}
2154
2155		deserializer.deserialize_str(StrVisitor)
2156	}
2157}
2158
2159impl serde::Serialize for CowStr<'_> {
2160	fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
2161	where
2162		S: serde::Serializer,
2163	{
2164		self.as_str().serialize(serializer)
2165	}
2166}
2167
2168impl<'de: 'a, 'a> serde::Deserialize<'de> for CowStr<'a> {
2169	fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
2170	where
2171		D: serde::Deserializer<'de>,
2172	{
2173		use serde::de::{Error, Unexpected};
2174
2175		struct CowStrVisitor;
2176
2177		impl<'de> serde::de::Visitor<'de> for CowStrVisitor {
2178			type Value = CowStr<'de>;
2179
2180			fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2181				formatter.write_str("a string")
2182			}
2183
2184			fn visit_str<E: Error>(self, v: &str) -> Result<Self::Value, E> {
2185				Ok(CowStr::Owned(StrMut::from(v)))
2186			}
2187
2188			fn visit_borrowed_str<E: Error>(self, v: &'de str) -> Result<Self::Value, E> {
2189				Ok(CowStr::Borrowed(v))
2190			}
2191
2192			fn visit_string<E: Error>(self, v: String) -> Result<Self::Value, E> {
2193				Ok(CowStr::Owned(StrMut::from(v)))
2194			}
2195
2196			fn visit_bytes<E: Error>(self, v: &[u8]) -> Result<Self::Value, E> {
2197				match str::from_utf8(v) {
2198					Ok(s) => Ok(CowStr::Owned(StrMut::from(s))),
2199					Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)),
2200				}
2201			}
2202
2203			fn visit_borrowed_bytes<E>(self, v: &'de [u8]) -> Result<Self::Value, E>
2204			where
2205				E: serde::de::Error,
2206			{
2207				match str::from_utf8(v) {
2208					Ok(s) => Ok(CowStr::Borrowed(s)),
2209					Err(_) => Err(Error::invalid_value(Unexpected::Bytes(v), &self)),
2210				}
2211			}
2212
2213			fn visit_byte_buf<E: Error>(self, v: Vec<u8>) -> Result<Self::Value, E> {
2214				match String::from_utf8(v) {
2215					Ok(s) => Ok(CowStr::Owned(StrMut::from(s))),
2216					Err(e) => Err(Error::invalid_value(Unexpected::Bytes(&e.into_bytes()), &self)),
2217				}
2218			}
2219		}
2220
2221		deserializer.deserialize_str(CowStrVisitor)
2222	}
2223}
2224
2225/// A clone-on-write smart pointer for strings with small string optimization.
2226///
2227/// The type `CowStr` is a smart pointer providing clone-on-write
2228/// functionality: it can enclose and provide immutable access to borrowed data,
2229/// and clone the data lazily when mutation or ownership is required.
2230///
2231/// `CowStr` implements `Deref`, which means that you can call non-mutating
2232/// methods directly on the data it encloses.
2233#[derive(Clone)]
2234pub enum CowStr<'a> {
2235	/// Borrowed data.
2236	Borrowed(&'a str),
2237	/// Owned data.
2238	Owned(StrMut),
2239}
2240
2241impl<'a> CowStr<'a> {
2242	/// Creates a new `CowStr` from a string slice.
2243	#[inline]
2244	pub const fn from_str(s: &'a str) -> Self {
2245		CowStr::Borrowed(s)
2246	}
2247
2248	/// Creates a new `CowStr` from an owned `StrMut`.
2249	#[inline]
2250	pub const fn from_owned(s: StrMut) -> Self {
2251		CowStr::Owned(s)
2252	}
2253
2254	/// Returns a `&str` slice of this `CowStr`.
2255	#[inline]
2256	pub fn as_str(&self) -> &str {
2257		match self {
2258			CowStr::Borrowed(s) => s,
2259			CowStr::Owned(s) => s.as_str(),
2260		}
2261	}
2262
2263	/// Returns the length of the string in bytes.
2264	#[inline]
2265	pub fn len(&self) -> usize {
2266		self.as_str().len()
2267	}
2268
2269	/// Returns `true` if the string has a length of zero bytes.
2270	#[inline]
2271	pub fn is_empty(&self) -> bool {
2272		self.as_str().is_empty()
2273	}
2274
2275	/// Returns true if the data is borrowed.
2276	#[inline]
2277	pub const fn is_borrowed(&self) -> bool {
2278		matches!(self, CowStr::Borrowed(_))
2279	}
2280
2281	/// Returns true if the data is owned.
2282	#[inline]
2283	pub const fn is_owned(&self) -> bool {
2284		matches!(self, CowStr::Owned(_))
2285	}
2286
2287	/// Assigns the slice passed to the `CowStr`.
2288	#[inline]
2289	pub fn assign_slice_ref(&mut self, subset: &'a str) {
2290		match self {
2291			CowStr::Owned(owned) => {
2292				// SAFETY: We copy valid UTF-8 bytes from `subset` to the beginning of
2293				// `owned`, then truncate to the copied length. The source is valid UTF-8,
2294				// so the result is valid UTF-8. The memory regions do not overlap
2295				// because subset is an independent string slice.
2296				unsafe {
2297					std::ptr::copy(subset.as_ptr(), owned.as_mut_ptr(), subset.len());
2298					owned.truncate(subset.len());
2299				}
2300			},
2301			CowStr::Borrowed(_) => *self = CowStr::Borrowed(subset),
2302		}
2303	}
2304
2305	/// Assigns self to be equal to the range given within the `CowStr` itself.
2306	#[inline]
2307	pub fn assign_range(&mut self, range: impl Into<std::ops::Range<usize>>) {
2308		let range = range.into();
2309		match self {
2310			CowStr::Owned(owned) => {
2311				let len = range.end - range.start;
2312				// SAFETY: We copy a substring of valid UTF-8 bytes within `owned` to the
2313				// beginning, then truncate. The range is validated by the caller (or will
2314				// panic on invalid access). Both pointers derive from one mutable borrow,
2315				// and ptr::copy handles the overlap. The resulting bytes are valid UTF-8
2316				// because they're a substring of valid UTF-8.
2317				unsafe {
2318					if range.start > 0 {
2319						let base = owned.as_str_mut().as_mut_ptr();
2320						std::ptr::copy(base.add(range.start).cast_const(), base, len);
2321					}
2322					owned.truncate(len);
2323				}
2324			},
2325			CowStr::Borrowed(s) => {
2326				*self = CowStr::Borrowed(&s[range]);
2327			},
2328		}
2329	}
2330
2331	/// Converts the `CowStr` into a `CowStr` that represents the specified
2332	/// range.
2333	///
2334	/// Clones the data if it is not already owned.
2335	///
2336	/// # Panics
2337	///
2338	/// Panics if the range is out of bounds.
2339	#[inline]
2340	pub fn into_range(self, range: impl Into<std::ops::Range<usize>>) -> Self {
2341		let range = range.into();
2342		match self {
2343			CowStr::Borrowed(s) => CowStr::Borrowed(&s[range]),
2344			CowStr::Owned(mut owned) => {
2345				let len = range.end - range.start;
2346				// SAFETY: We copy a substring of valid UTF-8 bytes within `owned` to the
2347				// beginning, then truncate. The range is validated by the caller (or will
2348				// panic on invalid access). Both pointers derive from one mutable borrow,
2349				// and ptr::copy handles the overlap. The resulting bytes are valid UTF-8
2350				// because they're a substring of valid UTF-8.
2351				unsafe {
2352					if range.start > 0 {
2353						let base = owned.as_str_mut().as_mut_ptr();
2354						std::ptr::copy(base.add(range.start).cast_const(), base, len);
2355					}
2356					owned.truncate(len);
2357				}
2358				CowStr::Owned(owned)
2359			},
2360		}
2361	}
2362
2363	/// Converts the `CowStr` into a `CowStr` that represents the specified
2364	/// slice reference.
2365	///
2366	/// Clones the data if it is not already owned.
2367	///
2368	/// # Panics
2369	///
2370	/// Panics if the slice reference is out of bounds.
2371	#[inline]
2372	pub fn into_slice_ref(self, subset: &'a str) -> Self {
2373		match self {
2374			CowStr::Borrowed(_) => CowStr::Borrowed(subset),
2375			CowStr::Owned(mut owned) => {
2376				// SAFETY: We copy valid UTF-8 bytes from `subset` to the beginning of
2377				// `owned`, then truncate to the copied length. The source is valid UTF-8,
2378				// so the result is valid UTF-8. The memory regions do not overlap
2379				// because subset is an independent string slice.
2380				unsafe {
2381					std::ptr::copy(subset.as_ptr(), owned.as_mut_ptr(), subset.len());
2382					owned.truncate(subset.len());
2383				}
2384				CowStr::Owned(owned)
2385			},
2386		}
2387	}
2388
2389	/// Converts the `CowStr` into an owned `CowStr`.
2390	#[inline]
2391	pub fn into_owned(self) -> CowStr<'static> {
2392		match self {
2393			CowStr::Borrowed(s) => CowStr::Owned(s.into()),
2394			CowStr::Owned(owned) => CowStr::Owned(owned),
2395		}
2396	}
2397
2398	/// Borrows the `CowStr` with a new lifetime.
2399	#[inline]
2400	pub fn borrow(&self) -> CowStr<'_> {
2401		match self {
2402			CowStr::Borrowed(s) => CowStr::Borrowed(s),
2403			CowStr::Owned(o) => CowStr::Borrowed(o.as_str()),
2404		}
2405	}
2406
2407	/// Returns a new `CowStr` with the given string appended.
2408	#[inline]
2409	pub fn push_str(&mut self, s: &str) {
2410		self.as_mut().push_str(s);
2411	}
2412
2413	/// Returns a new `CowStr` with the given character appended.
2414	#[inline]
2415	pub fn push(&mut self, c: char) {
2416		self.as_mut().push(c);
2417	}
2418
2419	/// Truncates the string to the specified length.
2420	#[inline]
2421	pub fn truncate(&mut self, len: usize) {
2422		if self.len() > len {
2423			match self {
2424				CowStr::Borrowed(s) => {
2425					*self = CowStr::Borrowed(s.split_at(len).0);
2426				},
2427				CowStr::Owned(s) => {
2428					s.truncate(len);
2429				},
2430			}
2431		}
2432	}
2433
2434	/// Trims the string in place, removing leading and trailing whitespace.
2435	///
2436	/// This method does not allocate if the `CowStr` is a borrowed `&str`.
2437	#[inline]
2438	pub fn trim(&mut self) {
2439		match self {
2440			CowStr::Borrowed(s) => {
2441				*self = CowStr::Borrowed(s.trim());
2442			},
2443			CowStr::Owned(s) => {
2444				let range = s
2445					.substr_range(s.trim())
2446					.expect("substr_range should not fail");
2447				self.assign_range(range);
2448			},
2449		}
2450	}
2451
2452	/// Trims the end of the string in place, removing trailing whitespace.
2453	///
2454	/// This method does not allocate if the `CowStr` is a borrowed `&str`.
2455	#[inline]
2456	pub fn trim_end(&mut self) {
2457		match self {
2458			CowStr::Borrowed(s) => {
2459				*self = CowStr::Borrowed(s.trim_end());
2460			},
2461			CowStr::Owned(s) => {
2462				let range = s
2463					.substr_range(s.trim_end())
2464					.expect("substr_range should not fail");
2465				self.assign_range(range);
2466			},
2467		}
2468	}
2469
2470	/// Trims the start of the string in place, removing leading whitespace.
2471	///
2472	/// This method does not allocate if the `CowStr` is a borrowed `&str`.
2473	#[inline]
2474	pub fn trim_start(&mut self) {
2475		match self {
2476			CowStr::Borrowed(s) => {
2477				*self = CowStr::Borrowed(s.trim_start());
2478			},
2479			CowStr::Owned(s) => {
2480				let range = s
2481					.substr_range(s.trim_start())
2482					.expect("substr_range should not fail");
2483				self.assign_range(range);
2484			},
2485		}
2486	}
2487
2488	/// Makes the string ASCII lowercase.
2489	#[inline]
2490	pub fn make_ascii_lowercase(&mut self) {
2491		// Only convert to owned if we actually need to modify
2492		if self.as_str().bytes().any(|b| b.is_ascii_uppercase()) {
2493			self.as_mut().make_ascii_lowercase();
2494		}
2495	}
2496
2497	/// Makes the string ASCII uppercase.
2498	#[inline]
2499	pub fn make_ascii_uppercase(&mut self) {
2500		// Only convert to owned if we actually need to modify
2501		if self.as_str().bytes().any(|b| b.is_ascii_lowercase()) {
2502			self.as_mut().make_ascii_uppercase();
2503		}
2504	}
2505}
2506
2507impl AsMut<StrMut> for CowStr<'_> {
2508	fn as_mut(&mut self) -> &mut StrMut {
2509		match self {
2510			CowStr::Borrowed(s) => {
2511				*self = CowStr::Owned(StrMut::new(s));
2512				match self {
2513					CowStr::Owned(owned) => owned,
2514					_ => unreachable!(),
2515				}
2516			},
2517			CowStr::Owned(owned) => owned,
2518		}
2519	}
2520}
2521
2522// ============================
2523// Conversions
2524// ============================
2525
2526impl<'a> From<&'a str> for CowStr<'a> {
2527	#[inline]
2528	fn from(s: &'a str) -> Self {
2529		CowStr::Borrowed(s)
2530	}
2531}
2532
2533impl From<StrMut> for CowStr<'_> {
2534	#[inline]
2535	fn from(s: StrMut) -> Self {
2536		CowStr::Owned(s)
2537	}
2538}
2539
2540impl From<Str> for CowStr<'_> {
2541	#[inline]
2542	fn from(s: Str) -> Self {
2543		CowStr::Owned(StrMut::from(s))
2544	}
2545}
2546
2547impl From<String> for CowStr<'_> {
2548	#[inline]
2549	fn from(s: String) -> Self {
2550		CowStr::Owned(StrMut::from(s))
2551	}
2552}
2553
2554impl<'a> From<Cow<'a, str>> for CowStr<'a> {
2555	#[inline]
2556	fn from(cow: Cow<'a, str>) -> Self {
2557		match cow {
2558			Cow::Borrowed(s) => CowStr::Borrowed(s),
2559			Cow::Owned(s) => CowStr::Owned(StrMut::from(s)),
2560		}
2561	}
2562}
2563
2564impl<'a> From<CowStr<'a>> for Cow<'a, str> {
2565	#[inline]
2566	fn from(cow: CowStr<'a>) -> Self {
2567		match cow {
2568			CowStr::Borrowed(s) => Cow::Borrowed(s),
2569			CowStr::Owned(s) => Cow::Owned(s.as_str().to_string()),
2570		}
2571	}
2572}
2573
2574impl<'a> From<CowStr<'a>> for Str {
2575	#[inline]
2576	fn from(cow: CowStr<'a>) -> Self {
2577		match cow {
2578			CowStr::Borrowed(s) => Self::from(s),
2579			CowStr::Owned(s) => Self::from(s),
2580		}
2581	}
2582}
2583
2584impl<'a> From<CowStr<'a>> for StrMut {
2585	#[inline]
2586	fn from(cow: CowStr<'a>) -> Self {
2587		match cow {
2588			CowStr::Borrowed(s) => Self::from(s),
2589			CowStr::Owned(s) => s,
2590		}
2591	}
2592}
2593
2594// ============================
2595// Deref and AsRef
2596// ============================
2597
2598impl Deref for CowStr<'_> {
2599	type Target = str;
2600
2601	#[inline]
2602	fn deref(&self) -> &str {
2603		self.as_str()
2604	}
2605}
2606
2607impl AsRef<str> for CowStr<'_> {
2608	#[inline]
2609	fn as_ref(&self) -> &str {
2610		self.as_str()
2611	}
2612}
2613
2614impl AsRef<[u8]> for CowStr<'_> {
2615	#[inline]
2616	fn as_ref(&self) -> &[u8] {
2617		self.as_str().as_bytes()
2618	}
2619}
2620
2621impl Borrow<str> for CowStr<'_> {
2622	#[inline]
2623	fn borrow(&self) -> &str {
2624		self.as_str()
2625	}
2626}
2627
2628// ============================
2629// Display and Debug
2630// ============================
2631
2632impl fmt::Display for CowStr<'_> {
2633	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2634		fmt::Display::fmt(self.as_str(), f)
2635	}
2636}
2637
2638impl fmt::Debug for CowStr<'_> {
2639	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2640		fmt::Debug::fmt(self.as_str(), f)
2641	}
2642}
2643
2644// ============================
2645// Equality
2646// ============================
2647
2648impl PartialEq for CowStr<'_> {
2649	#[inline]
2650	fn eq(&self, other: &Self) -> bool {
2651		self.as_str() == other.as_str()
2652	}
2653}
2654
2655impl Eq for CowStr<'_> {}
2656
2657impl PartialEq<str> for CowStr<'_> {
2658	#[inline]
2659	fn eq(&self, other: &str) -> bool {
2660		self.as_str() == other
2661	}
2662}
2663
2664impl PartialEq<CowStr<'_>> for str {
2665	#[inline]
2666	fn eq(&self, other: &CowStr<'_>) -> bool {
2667		self == other.as_str()
2668	}
2669}
2670
2671impl PartialEq<&str> for CowStr<'_> {
2672	#[inline]
2673	fn eq(&self, other: &&str) -> bool {
2674		self.as_str() == *other
2675	}
2676}
2677
2678impl PartialEq<CowStr<'_>> for &str {
2679	#[inline]
2680	fn eq(&self, other: &CowStr<'_>) -> bool {
2681		*self == other.as_str()
2682	}
2683}
2684
2685impl PartialEq<String> for CowStr<'_> {
2686	#[inline]
2687	fn eq(&self, other: &String) -> bool {
2688		self.as_str() == other.as_str()
2689	}
2690}
2691
2692impl PartialEq<CowStr<'_>> for String {
2693	#[inline]
2694	fn eq(&self, other: &CowStr<'_>) -> bool {
2695		self.as_str() == other.as_str()
2696	}
2697}
2698
2699impl PartialEq<Str> for CowStr<'_> {
2700	#[inline]
2701	fn eq(&self, other: &Str) -> bool {
2702		self.as_str() == other.as_str()
2703	}
2704}
2705
2706impl PartialEq<CowStr<'_>> for Str {
2707	#[inline]
2708	fn eq(&self, other: &CowStr<'_>) -> bool {
2709		self.as_str() == other.as_str()
2710	}
2711}
2712
2713impl PartialEq<StrMut> for CowStr<'_> {
2714	#[inline]
2715	fn eq(&self, other: &StrMut) -> bool {
2716		self.as_str() == other.as_str()
2717	}
2718}
2719
2720impl PartialEq<CowStr<'_>> for StrMut {
2721	#[inline]
2722	fn eq(&self, other: &CowStr<'_>) -> bool {
2723		self.as_str() == other.as_str()
2724	}
2725}
2726
2727// ============================
2728// Ordering
2729// ============================
2730
2731impl PartialOrd for CowStr<'_> {
2732	#[inline]
2733	fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
2734		Some(self.cmp(other))
2735	}
2736}
2737
2738impl Ord for CowStr<'_> {
2739	#[inline]
2740	fn cmp(&self, other: &Self) -> Ordering {
2741		self.as_str().cmp(other.as_str())
2742	}
2743}
2744
2745impl PartialOrd<str> for CowStr<'_> {
2746	#[inline(always)]
2747	fn partial_cmp(&self, other: &str) -> Option<Ordering> {
2748		self.as_str().partial_cmp(other)
2749	}
2750}
2751
2752impl PartialOrd<CowStr<'_>> for str {
2753	#[inline(always)]
2754	fn partial_cmp(&self, other: &CowStr<'_>) -> Option<Ordering> {
2755		self.partial_cmp(other.as_str())
2756	}
2757}
2758
2759impl PartialOrd<&str> for CowStr<'_> {
2760	#[inline(always)]
2761	fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
2762		self.partial_cmp(*other)
2763	}
2764}
2765
2766impl PartialOrd<CowStr<'_>> for &str {
2767	#[inline(always)]
2768	fn partial_cmp(&self, other: &CowStr<'_>) -> Option<Ordering> {
2769		(*self).partial_cmp(other)
2770	}
2771}
2772
2773// ============================
2774// Hash
2775// ============================
2776
2777impl Hash for CowStr<'_> {
2778	#[inline]
2779	fn hash<H: Hasher>(&self, state: &mut H) {
2780		self.as_str().hash(state);
2781	}
2782}
2783
2784// ============================
2785// Default
2786// ============================
2787
2788impl Default for CowStr<'_> {
2789	#[inline]
2790	fn default() -> Self {
2791		CowStr::Owned(StrMut::default())
2792	}
2793}
2794
2795// ============================
2796// Tests
2797// ============================
2798
2799#[cfg(test)]
2800mod tests {
2801	use serde_json as json;
2802
2803	use super::*;
2804
2805	const PREFIX: &str = "prefix__";
2806	const REMAINDER: &str = "abcdefghijklmnopjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
2807	const LONG_TEXT: &str = "prefix__abcdefghijklmnopjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
2808	const SPACED: &str = "   prefix__abcdefghijklmnopjklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
2809
2810	fn heap_ptr(s: &Str) -> (*const u8, usize) {
2811		match &s.0 {
2812			Repr::Heap(data) => (data.inner().as_ptr(), data.len()),
2813			_ => panic!("expected heap representation"),
2814		}
2815	}
2816
2817	#[test]
2818	fn shared_buffer_prefix_slice_is_not_equal_to_parent() {
2819		let parent = Str::new(LONG_TEXT);
2820		let prefix = parent.slice(..PREFIX.len());
2821		// Both share the parent's start pointer; equality must still compare
2822		// lengths, not just pointer identity.
2823		assert_eq!(heap_ptr(&prefix).0, heap_ptr(&parent).0);
2824		assert_ne!(prefix, parent);
2825		assert_ne!(parent, prefix);
2826		assert_eq!(prefix, Str::new(PREFIX));
2827		assert_eq!(parent, parent.slice(..));
2828	}
2829
2830	#[test]
2831	fn strip_prefix_reuses_heap_storage() {
2832		let value = Str::new(LONG_TEXT);
2833		assert!(value.is_spilled());
2834
2835		let (orig_ptr, orig_len) = heap_ptr(&value);
2836		assert_eq!(orig_len, LONG_TEXT.len());
2837
2838		let remainder = value.strip_prefix(PREFIX).expect("prefix matches");
2839		assert_eq!(remainder.as_str(), REMAINDER);
2840
2841		let (rem_ptr, rem_len) = heap_ptr(&remainder);
2842		assert_eq!(rem_len, REMAINDER.len());
2843
2844		// SAFETY: both pointers originate from the same allocation provided by
2845		// bytes::Bytes, so offset_from is valid.
2846		unsafe {
2847			assert_eq!(rem_ptr.offset_from(orig_ptr) as usize, PREFIX.len());
2848		}
2849	}
2850
2851	#[test]
2852	fn split_at_reuses_heap_storage() {
2853		let value = Str::new(LONG_TEXT);
2854		assert!(value.is_spilled());
2855
2856		let split_at = PREFIX.len();
2857		let (left, right) = value.split_at(split_at);
2858
2859		assert_eq!(left.as_str(), &LONG_TEXT[..split_at]);
2860		assert_eq!(right.as_str(), &LONG_TEXT[split_at..]);
2861
2862		let (orig_ptr, _) = heap_ptr(&value);
2863		let (left_ptr, left_len) = heap_ptr(&left);
2864		let (right_ptr, right_len) = heap_ptr(&right);
2865
2866		assert_eq!(left_len, split_at);
2867		assert_eq!(right_len, LONG_TEXT.len() - split_at);
2868
2869		// SAFETY: All pointers originate from the same allocation provided by
2870		// bytes::Bytes, so offset_from is valid.
2871		unsafe {
2872			assert_eq!(left_ptr.offset_from(orig_ptr) as usize, 0);
2873			assert_eq!(right_ptr.offset_from(orig_ptr) as usize, split_at);
2874		}
2875	}
2876
2877	#[test]
2878	fn trim_start_reuses_heap_storage() {
2879		let value = Str::new(SPACED);
2880		assert!(value.is_spilled());
2881
2882		let trimmed = value.trim_start();
2883		assert_eq!(trimmed.as_str(), LONG_TEXT);
2884
2885		let (orig_ptr, _) = heap_ptr(&value);
2886		let (trim_ptr, _) = heap_ptr(&trimmed);
2887
2888		// SAFETY: Both pointers originate from the same allocation provided by
2889		// bytes::Bytes, so offset_from is valid.
2890		unsafe {
2891			assert_eq!(trim_ptr.offset_from(orig_ptr) as usize, 3);
2892		}
2893	}
2894
2895	#[test]
2896	fn test_add_operations() {
2897		// Test Str + &str
2898		let s1 = Str::new("hello");
2899		let result = s1 + " world";
2900		assert_eq!(result.as_str(), "hello world");
2901
2902		// Test &str + Str
2903		let s2 = Str::new("world");
2904		let result = "hello " + s2;
2905		assert_eq!(result.as_str(), "hello world");
2906
2907		// Test &Str + &str
2908		let s3 = Str::new("hello");
2909		let result = &s3 + " world";
2910		assert_eq!(result.as_str(), "hello world");
2911
2912		// Test &str + &Str
2913		let s4 = Str::new("world");
2914		let result = "hello " + &s4;
2915		assert_eq!(result.as_str(), "hello world");
2916
2917		// Test StrMut + &str
2918		let m1 = StrMut::new("hello");
2919		let result = m1 + " world";
2920		assert_eq!(result.as_str(), "hello world");
2921
2922		// Test &str + StrMut
2923		let m2 = StrMut::new("world");
2924		let result = "hello " + m2;
2925		assert_eq!(result.as_str(), "hello world");
2926
2927		// Test &StrMut + &str
2928		let m3 = StrMut::new("hello");
2929		let result = &m3 + " world";
2930		assert_eq!(result.as_str(), "hello world");
2931
2932		// Test &str + &StrMut
2933		let m4 = StrMut::new("world");
2934		let result = "hello " + &m4;
2935		assert_eq!(result.as_str(), "hello world");
2936
2937		// Test with heap-allocated strings
2938		let long = Str::new("this is a very long string that will be heap allocated");
2939		let result = &long + " and more";
2940		assert_eq!(
2941			result.as_str(),
2942			"this is a very long string that will be heap allocated and more"
2943		);
2944	}
2945
2946	#[test]
2947	fn test_insert_inline_to_heap_promotion() {
2948		// Test that insert properly promotes from inline to heap when needed
2949		let mut s = StrMut::new("hello world");
2950		assert!(!s.is_spilled()); // Should be inline
2951
2952		// Insert something that will exceed inline capacity
2953		s.insert(6, "beautiful and wonderful ");
2954		assert_eq!(s.as_str(), "hello beautiful and wonderful world");
2955		assert!(s.is_spilled()); // Should now be on heap
2956
2957		// Test insert at the beginning
2958		let mut s = StrMut::new("world");
2959		s.insert(0, "hello ");
2960		assert_eq!(s.as_str(), "hello world");
2961
2962		// Test insert at the end
2963		let mut s = StrMut::new("hello");
2964		s.insert(5, " world");
2965		assert_eq!(s.as_str(), "hello world");
2966
2967		// Test insert that triggers promotion with more text
2968		let mut s = StrMut::new("12345678901234567890"); // 20 chars, near limit
2969		s.insert(10, "ABCDE"); // This will exceed inline capacity
2970		assert_eq!(s.as_str(), "1234567890ABCDE1234567890");
2971		assert!(s.is_spilled());
2972	}
2973
2974	#[test]
2975	fn test_cow_basic_operations() {
2976		// Test borrowed variant
2977		let s = "hello world";
2978		let cow = CowStr::from(s);
2979		assert!(cow.is_borrowed());
2980		assert!(!cow.is_owned());
2981		assert_eq!(cow.as_str(), "hello world");
2982		assert_eq!(cow.len(), 11);
2983		assert!(!cow.is_empty());
2984
2985		// Test owned variant
2986		let mut_str = StrMut::new("hello");
2987		let cow = CowStr::from(mut_str);
2988		assert!(!cow.is_borrowed());
2989		assert!(cow.is_owned());
2990		assert_eq!(cow.as_str(), "hello");
2991	}
2992
2993	#[test]
2994	fn test_cow_to_mut() {
2995		// Start with borrowed
2996		let s = "hello";
2997		let mut cow = CowStr::from(s);
2998		assert!(cow.is_borrowed());
2999
3000		// Convert to owned via as_mut
3001		let mutable = cow.as_mut();
3002		mutable.push_str(" world");
3003		assert!(cow.is_owned());
3004		assert_eq!(cow.as_str(), "hello world");
3005
3006		// Second call to as_mut doesn't clone again
3007		let mutable2 = cow.as_mut();
3008		mutable2.push_str("!");
3009		assert_eq!(cow.as_str(), "hello world!");
3010	}
3011
3012	#[test]
3013	fn test_cow_assign_slice_ref() {
3014		let original = "hello world";
3015
3016		// Test with borrowed
3017		let mut cow = CowStr::from(original);
3018		cow.assign_slice_ref("goodbye");
3019		assert!(cow.is_borrowed());
3020		assert_eq!(cow.as_str(), "goodbye");
3021
3022		// Test with owned
3023		let mut cow = CowStr::from(StrMut::new("hello world"));
3024		cow.assign_slice_ref("bye");
3025		assert!(cow.is_owned());
3026		assert_eq!(cow.as_str(), "bye");
3027	}
3028
3029	#[test]
3030	fn test_cow_assign_range() {
3031		// Test with borrowed
3032		let mut cow = CowStr::from("hello world");
3033		cow.assign_range(0..5);
3034		assert!(cow.is_borrowed());
3035		assert_eq!(cow.as_str(), "hello");
3036
3037		// Test with owned
3038		let mut cow = CowStr::from(StrMut::new("hello world"));
3039		cow.assign_range(6..11);
3040		assert!(cow.is_owned());
3041		assert_eq!(cow.as_str(), "world");
3042
3043		// Test range in middle
3044		let mut cow = CowStr::from(StrMut::new("hello world"));
3045		cow.assign_range(3..8);
3046		assert_eq!(cow.as_str(), "lo wo");
3047	}
3048
3049	#[test]
3050	fn test_cow_into_range() {
3051		// Test with borrowed
3052		let cow = CowStr::from("hello world");
3053		let new_cow = cow.into_range(0..5);
3054		assert!(new_cow.is_borrowed());
3055		assert_eq!(new_cow.as_str(), "hello");
3056
3057		// Test with owned
3058		let cow = CowStr::from(StrMut::new("hello world"));
3059		let new_cow = cow.into_range(6..11);
3060		assert!(new_cow.is_owned());
3061		assert_eq!(new_cow.as_str(), "world");
3062	}
3063
3064	#[test]
3065	fn test_cow_into_slice_ref() {
3066		let original = "hello world";
3067
3068		// Test with borrowed
3069		let cow = CowStr::from(original);
3070		let subset = &original[6..11];
3071		let new_cow = cow.into_slice_ref(subset);
3072		assert!(new_cow.is_borrowed());
3073		assert_eq!(new_cow.as_str(), "world");
3074
3075		// Test with owned
3076		let cow = CowStr::from(StrMut::new("hello world"));
3077		let new_cow = cow.into_slice_ref("new");
3078		assert!(new_cow.is_owned());
3079		assert_eq!(new_cow.as_str(), "new");
3080	}
3081
3082	#[test]
3083	fn test_cow_mutating_operations() {
3084		// Test push_str
3085		let mut cow = CowStr::from("hello");
3086		cow.push_str(" world");
3087		assert!(cow.is_owned());
3088		assert_eq!(cow.as_str(), "hello world");
3089
3090		// Test push
3091		let mut cow = CowStr::from("hello");
3092		cow.push('!');
3093		assert_eq!(cow.as_str(), "hello!");
3094
3095		// Test truncate with borrowed
3096		let mut cow = CowStr::from("hello world");
3097		cow.truncate(5);
3098		assert!(cow.is_borrowed());
3099		assert_eq!(cow.as_str(), "hello");
3100
3101		// Test truncate with owned
3102		let mut cow = CowStr::from(StrMut::new("hello world"));
3103		cow.truncate(5);
3104		assert!(cow.is_owned());
3105		assert_eq!(cow.as_str(), "hello");
3106	}
3107
3108	#[test]
3109	fn test_cow_trim_operations() {
3110		// Test trim with borrowed
3111		let mut cow = CowStr::from("  hello world  ");
3112		cow.trim();
3113		assert!(cow.is_borrowed());
3114		assert_eq!(cow.as_str(), "hello world");
3115
3116		// Test trim with owned
3117		let mut cow = CowStr::from(StrMut::new("  hello world  "));
3118		cow.trim();
3119		assert!(cow.is_owned());
3120		assert_eq!(cow.as_str(), "hello world");
3121
3122		// Test trim_start with borrowed
3123		let mut cow = CowStr::from("  hello");
3124		cow.trim_start();
3125		assert!(cow.is_borrowed());
3126		assert_eq!(cow.as_str(), "hello");
3127
3128		// Test trim_start with owned
3129		let mut cow = CowStr::from(StrMut::new("  hello"));
3130		cow.trim_start();
3131		assert!(cow.is_owned());
3132		assert_eq!(cow.as_str(), "hello");
3133
3134		// Test trim_end with borrowed
3135		let mut cow = CowStr::from("hello  ");
3136		cow.trim_end();
3137		assert!(cow.is_borrowed());
3138		assert_eq!(cow.as_str(), "hello");
3139
3140		// Test trim_end with owned
3141		let mut cow = CowStr::from(StrMut::new("hello  "));
3142		cow.trim_end();
3143		assert!(cow.is_owned());
3144		assert_eq!(cow.as_str(), "hello");
3145	}
3146
3147	#[test]
3148	fn test_cow_ascii_case_conversion() {
3149		// Test lowercase - should not convert to owned if no changes needed
3150		let mut cow = CowStr::from("hello");
3151		cow.make_ascii_lowercase();
3152		assert!(cow.is_borrowed()); // Still borrowed since no uppercase letters
3153
3154		let mut cow = CowStr::from("HELLO");
3155		cow.make_ascii_lowercase();
3156		assert!(cow.is_owned());
3157		assert_eq!(cow.as_str(), "hello");
3158
3159		// Test uppercase
3160		let mut cow = CowStr::from("HELLO");
3161		cow.make_ascii_uppercase();
3162		assert!(cow.is_borrowed()); // Still borrowed since no lowercase letters
3163
3164		let mut cow = CowStr::from("hello");
3165		cow.make_ascii_uppercase();
3166		assert!(cow.is_owned());
3167		assert_eq!(cow.as_str(), "HELLO");
3168	}
3169
3170	#[test]
3171	fn test_cow_equality() {
3172		let cow1 = CowStr::from("hello");
3173		let cow2 = CowStr::from(StrMut::new("hello"));
3174
3175		assert_eq!(cow1, cow2);
3176		assert_eq!(cow1, "hello");
3177		assert_eq!("hello", cow1);
3178		assert_eq!(cow1, String::from("hello"));
3179		assert_eq!(cow1, Str::new("hello"));
3180		assert_eq!(cow1, StrMut::new("hello"));
3181	}
3182
3183	#[test]
3184	fn test_cow_ordering() {
3185		let cow1 = CowStr::from("apple");
3186		let cow2 = CowStr::from("banana");
3187		let cow3 = CowStr::from(StrMut::new("apple"));
3188
3189		assert!(cow1 < cow2);
3190		assert!(cow2 > cow1);
3191		assert_eq!(cow1.cmp(&cow3), std::cmp::Ordering::Equal);
3192	}
3193
3194	#[test]
3195	fn test_cow_hash() {
3196		use std::{
3197			collections::hash_map::DefaultHasher,
3198			hash::{Hash, Hasher},
3199		};
3200
3201		let cow1 = CowStr::from("hello");
3202		let cow2 = CowStr::from(StrMut::new("hello"));
3203
3204		let mut hasher1 = DefaultHasher::new();
3205		cow1.hash(&mut hasher1);
3206		let hash1 = hasher1.finish();
3207
3208		let mut hasher2 = DefaultHasher::new();
3209		cow2.hash(&mut hasher2);
3210		let hash2 = hasher2.finish();
3211
3212		assert_eq!(hash1, hash2);
3213	}
3214
3215	#[test]
3216	fn test_cow_into_owned() {
3217		// From borrowed
3218		let cow = CowStr::from("hello");
3219		let owned = cow.into_str_mut();
3220		assert_eq!(owned.as_str(), "hello");
3221
3222		// From already owned
3223		let cow = CowStr::from(StrMut::new("world"));
3224		let owned = cow.into_str_mut();
3225		assert_eq!(owned.as_str(), "world");
3226	}
3227
3228	#[test]
3229	fn test_cow_into_str() {
3230		let cow = CowStr::from("hello");
3231		let string = cow.into_str();
3232		assert_eq!(string.as_str(), "hello");
3233	}
3234
3235	#[test]
3236	fn test_cow_cow_conversion() {
3237		// From Cow to CowStr
3238		let std_cow = Cow::Borrowed("hello");
3239		let cow: CowStr = std_cow.into();
3240		assert!(cow.is_borrowed());
3241
3242		let std_cow = Cow::<str>::Owned(String::from("world"));
3243		let cow: CowStr = std_cow.into();
3244		assert!(cow.is_owned());
3245
3246		// From CowStr to Cow
3247		let cow = CowStr::from("hello");
3248		let std_cow: Cow<str> = cow.into();
3249		assert!(matches!(std_cow, Cow::Borrowed(_)));
3250	}
3251
3252	#[test]
3253	fn test_cow_from_conversions() {
3254		// From Str
3255		let string = Str::new("hello");
3256		let cow: CowStr = string.into();
3257		assert!(cow.is_owned());
3258		assert_eq!(cow.as_str(), "hello");
3259
3260		// From String
3261		let string = String::from("world");
3262		let cow: CowStr = string.into();
3263		assert!(cow.is_owned());
3264		assert_eq!(cow.as_str(), "world");
3265
3266		// Into Str
3267		let cow = CowStr::from("test");
3268		let string: Str = cow.into();
3269		assert_eq!(string.as_str(), "test");
3270
3271		// Into StrMut
3272		let cow = CowStr::from("test");
3273		let string_mut: StrMut = cow.into();
3274		assert_eq!(string_mut.as_str(), "test");
3275	}
3276
3277	#[test]
3278	fn test_cow_default() {
3279		let cow: CowStr = Default::default();
3280		assert!(cow.is_owned());
3281		assert_eq!(cow.as_str(), "");
3282		assert!(cow.is_empty());
3283	}
3284
3285	#[test]
3286	fn test_cow_deref_and_borrow() {
3287		let cow = CowStr::from("hello world");
3288
3289		// Test Deref
3290		assert_eq!(&*cow, "hello world");
3291
3292		// Test AsRef<str>
3293		let s: &str = cow.as_ref();
3294		assert_eq!(s, "hello world");
3295
3296		// Test AsRef<[u8]>
3297		let bytes: &[u8] = cow.as_ref();
3298		assert_eq!(bytes, b"hello world");
3299	}
3300
3301	#[test]
3302	fn test_cow_serde() {
3303		// Test serialization
3304		let cow = CowStr::from("hello world");
3305		let json = json::to_string(&cow).unwrap();
3306		assert_eq!(json, r#""hello world""#);
3307
3308		// Test deserialization - will succesfully borrow!
3309		let deserialized: CowStr = json::from_str(&json).unwrap();
3310		assert!(!deserialized.is_owned());
3311		assert_eq!(deserialized.as_str(), "hello world");
3312
3313		// Test with owned variant
3314		let cow = CowStr::from(StrMut::new("test"));
3315		let json = json::to_string(&cow).unwrap();
3316		assert_eq!(json, r#""test""#);
3317	}
3318
3319	// ============================
3320	// Empty and Boundary Tests (from lib/core/tests/string.rs)
3321	// ============================
3322
3323	#[test]
3324	fn test_empty_strings() {
3325		// Empty Str
3326		let s = Str::new("");
3327		assert!(s.is_empty());
3328		assert_eq!(s.len(), 0);
3329		assert!(!s.is_spilled());
3330		assert_eq!(s.as_str(), "");
3331
3332		// Empty StrMut
3333		let mut m = StrMut::new("");
3334		assert!(m.is_empty());
3335		assert_eq!(m.len(), 0);
3336		assert!(!m.is_spilled());
3337		m.push_str("");
3338		assert!(m.is_empty());
3339
3340		// Operations on empty
3341		assert_eq!(s.trim(), "");
3342		assert_eq!(s.trim_start(), "");
3343		assert_eq!(s.trim_end(), "");
3344		assert_eq!(s.strip_prefix("x"), None);
3345		assert_eq!(s.strip_suffix("x"), None);
3346
3347		let (l, r) = s.split_at(0);
3348		assert!(l.is_empty());
3349		assert!(r.is_empty());
3350
3351		// Empty split
3352		let parts: Vec<_> = s.split("x").collect();
3353		assert_eq!(parts.len(), 1);
3354		assert_eq!(parts[0], "");
3355	}
3356
3357	#[test]
3358	fn test_exact_inline_capacity() {
3359		// 23 bytes - maximum inline capacity
3360		let text = "12345678901234567890123"; // exactly 23 bytes
3361		assert_eq!(text.len(), 23);
3362
3363		let s = Str::new(text);
3364		assert!(!s.is_spilled());
3365		assert_eq!(s.len(), 23);
3366		assert_eq!(s.as_str(), text);
3367
3368		let m = StrMut::new(text);
3369		assert!(!m.is_spilled());
3370		assert_eq!(m.len(), 23);
3371	}
3372
3373	#[test]
3374	fn test_boundary_24_bytes() {
3375		// 24 bytes - first to require heap
3376		let text = "123456789012345678901234"; // 24 bytes
3377		assert_eq!(text.len(), 24);
3378
3379		let s = Str::new(text);
3380		assert!(s.is_spilled());
3381		assert_eq!(s.len(), 24);
3382		assert_eq!(s.as_str(), text);
3383
3384		let m = StrMut::new(text);
3385		assert!(m.is_spilled());
3386		assert_eq!(m.len(), 24);
3387	}
3388
3389	#[test]
3390	fn test_slice_boundaries() {
3391		let text = "0123456789";
3392		let s = Str::new(text);
3393
3394		// Full range
3395		assert_eq!(s.slice(..), text);
3396		assert_eq!(s.slice(0..10), text);
3397
3398		// Empty slices
3399		assert_eq!(s.slice(0..0), "");
3400		assert_eq!(s.slice(5..5), "");
3401		assert_eq!(s.slice(10..10), "");
3402
3403		// Single char
3404		assert_eq!(s.slice(0..1), "0");
3405		assert_eq!(s.slice(9..10), "9");
3406
3407		// Prefix/suffix
3408		assert_eq!(s.slice(..5), "01234");
3409		assert_eq!(s.slice(5..), "56789");
3410	}
3411
3412	#[test]
3413	#[should_panic(expected = "self.is_char_boundary(new_len)")]
3414	fn test_truncate_non_char_boundary_inline() {
3415		let mut s = Str::new("hello world δΈ–η•Œ");
3416		s.truncate(13); // Middle of 'δΈ–' (3 bytes)
3417	}
3418
3419	#[test]
3420	#[should_panic(expected = "Index is not on a char boundary")]
3421	fn test_truncate_non_char_boundary_heap() {
3422		let mut s = Str::new("hello world hello world δΈ–η•Œ");
3423		s.truncate(26); // Middle of 'δΈ–'
3424	}
3425
3426	// ============================
3427	// UTF-8 Validation Tests
3428	// ============================
3429
3430	#[test]
3431	fn test_from_utf8_valid() {
3432		let valid = b"hello world";
3433		let s = Str::from_utf8(valid).unwrap();
3434		assert_eq!(s.as_str(), "hello world");
3435
3436		let valid_utf8 = "hello δΈ–η•Œ 🌍".as_bytes();
3437		let s = Str::from_utf8(valid_utf8).unwrap();
3438		assert_eq!(s.as_str(), "hello δΈ–η•Œ 🌍");
3439	}
3440
3441	#[test]
3442	fn test_from_utf8_invalid() {
3443		let invalid = &[0xff, 0xfe, 0xfd];
3444		assert!(Str::from_utf8(invalid).is_err());
3445
3446		let invalid = &[0xc0, 0x80]; // Overlong encoding
3447		assert!(Str::from_utf8(invalid).is_err());
3448	}
3449
3450	#[test]
3451	fn test_from_utf8_lossy() {
3452		let valid = Str::from_utf8_lossy("hello δΈ–η•Œ".as_bytes());
3453		assert_eq!(valid.as_str(), "hello δΈ–η•Œ");
3454
3455		let invalid = Str::from_utf8_lossy(b"hello \xff world");
3456		assert_eq!(invalid.as_str(), "hello οΏ½ world");
3457	}
3458
3459	#[test]
3460	fn test_from_utf8_owned_valid() {
3461		let valid = bytes::Bytes::from("hello world");
3462		let s = Str::from_utf8_owned(valid).unwrap();
3463		assert_eq!(s.as_str(), "hello world");
3464		assert!(s.is_spilled());
3465	}
3466
3467	#[test]
3468	fn test_from_utf8_owned_invalid() {
3469		let invalid = bytes::Bytes::from_static(&[0xff, 0xfe, 0xfd]);
3470		assert!(Str::from_utf8_owned(invalid).is_err());
3471	}
3472
3473	#[test]
3474	fn test_from_utf8_mut_valid() {
3475		let valid = b"hello";
3476		let m = StrMut::from_utf8(valid).unwrap();
3477		assert_eq!(m.as_str(), "hello");
3478	}
3479
3480	#[test]
3481	fn test_from_utf8_mut_invalid() {
3482		let invalid = &[0xff, 0xfe];
3483		assert!(StrMut::from_utf8(invalid).is_err());
3484	}
3485
3486	#[test]
3487	fn test_multibyte_char_boundaries() {
3488		// Emoji (4 bytes) + Chinese (3 bytes each)
3489		let text = "πŸŒδΈ–η•Œ";
3490		let s = Str::new(text);
3491		assert_eq!(s.len(), 10); // 4 + 3 + 3
3492
3493		// Split at valid boundaries
3494		let (l, r) = s.split_at(4);
3495		assert_eq!(l.as_str(), "🌍");
3496		assert_eq!(r.as_str(), "δΈ–η•Œ");
3497
3498		// Truncate at valid boundary
3499		let mut s2 = Str::new(text);
3500		s2.truncate(4);
3501		assert_eq!(s2.as_str(), "🌍");
3502	}
3503
3504	#[test]
3505	#[should_panic(expected = "byte index 1 is not a char boundary")]
3506	fn test_split_at_invalid_boundary() {
3507		let s = Str::new("δΈ–η•Œ");
3508		let _ = s.split_at(1); // Middle of 'δΈ–' (3 bytes)
3509	}
3510
3511	// ============================
3512	// Error Path Tests
3513	// ============================
3514
3515	#[test]
3516	#[should_panic(expected = "len <= INLINE_CAP")]
3517	fn test_new_inline_panic() {
3518		let too_long = "123456789012345678901234"; // 24 bytes
3519		let _ = Str::new_inline(too_long);
3520	}
3521
3522	#[test]
3523	#[should_panic(expected = "len <= INLINE_CAP")]
3524	fn test_new_inline_mut_panic() {
3525		let too_long = "123456789012345678901234";
3526		let _ = StrMut::new_inline(too_long);
3527	}
3528
3529	#[test]
3530	#[should_panic(expected = "index is not on a valid UTF-8 character boundary")]
3531	fn test_insert_non_char_boundary_inline() {
3532		let mut m = StrMut::new("δΈ–η•Œ");
3533		m.insert(1, "x"); // Middle of 'δΈ–'
3534	}
3535
3536	#[test]
3537	#[should_panic(expected = "index is not on a valid UTF-8 character boundary")]
3538	fn test_insert_non_char_boundary_heap() {
3539		let mut m = StrMut::new("hello world hello world δΈ–η•Œ");
3540		m.insert(25, "x"); // Middle of 'δΈ–'
3541	}
3542
3543	#[test]
3544	fn test_try_into_mut_success_inline() {
3545		let s = Str::new("hello");
3546		let m = s.try_into_mut().unwrap();
3547		assert_eq!(m.as_str(), "hello");
3548		assert!(!m.is_spilled());
3549	}
3550
3551	#[test]
3552	fn test_try_into_mut_success_heap_unique() {
3553		let s = Str::new("hello world hello world!!");
3554		let m = s.try_into_mut().unwrap();
3555		assert_eq!(m.as_str(), "hello world hello world!!");
3556		assert!(m.is_spilled());
3557	}
3558
3559	#[test]
3560	fn test_try_into_mut_failure_shared() {
3561		let s = Str::new("hello world hello world!!");
3562		let s2 = s.clone();
3563
3564		// Should fail because Bytes is shared
3565		let result = s.try_into_mut();
3566		assert!(result.is_err());
3567
3568		// Original value should be recoverable
3569		let original = result.unwrap_err();
3570		assert_eq!(original.as_str(), "hello world hello world!!");
3571		assert_eq!(s2.as_str(), "hello world hello world!!");
3572	}
3573
3574	// ============================
3575	// Inline→Heap Transition Tests
3576	// ============================
3577
3578	#[test]
3579	fn test_push_str_inline_to_heap() {
3580		let mut m = StrMut::new("12345678901234567890"); // 20 bytes
3581		assert!(!m.is_spilled());
3582
3583		m.push_str("1234"); // Total 24 bytes
3584		assert!(m.is_spilled());
3585		assert_eq!(m.as_str(), "123456789012345678901234");
3586	}
3587
3588	#[test]
3589	fn test_push_char_inline_to_heap() {
3590		let mut m = StrMut::new("1234567890123456789012"); // 22 bytes
3591		assert!(!m.is_spilled());
3592
3593		m.push('x');
3594		assert!(!m.is_spilled()); // 23 bytes, still inline
3595
3596		m.push('y');
3597		assert!(m.is_spilled()); // 24 bytes, now heap
3598		assert_eq!(m.as_str(), "1234567890123456789012xy");
3599	}
3600
3601	#[test]
3602	fn test_push_multibyte_char_promotion() {
3603		let mut m = StrMut::new("12345678901234567890"); // 20 bytes
3604		assert!(!m.is_spilled());
3605
3606		m.push('🌍'); // 4 bytes emoji
3607		assert!(m.is_spilled()); // 24 bytes total
3608		assert_eq!(m.as_str(), "12345678901234567890🌍");
3609	}
3610
3611	#[test]
3612	fn test_reserve_triggers_promotion() {
3613		let mut m = StrMut::new("hello"); // 5 bytes inline
3614		assert!(!m.is_spilled());
3615
3616		m.reserve(20); // Reserve 20 more, total capacity 25
3617		assert!(m.is_spilled());
3618		assert_eq!(m.as_str(), "hello");
3619
3620		// Should still have capacity
3621		m.push_str("12345678901234567890"); // 25 bytes total
3622		assert_eq!(m.as_str(), "hello12345678901234567890");
3623	}
3624
3625	#[test]
3626	fn test_sequential_operations_promotion() {
3627		let mut m = StrMut::new("abc");
3628		assert!(!m.is_spilled());
3629
3630		for _ in 0..5 {
3631			m.push_str("1234"); // 4 bytes each
3632		}
3633		// Total: 3 + 20 = 23 bytes (still inline)
3634		assert!(!m.is_spilled());
3635
3636		m.push('x');
3637		assert!(m.is_spilled()); // 24 bytes
3638	}
3639
3640	// ============================
3641	// Slicing & Zero-Copy Tests
3642	// ============================
3643
3644	#[test]
3645	fn test_strip_prefix_none() {
3646		let s = Str::new("hello world");
3647		assert_eq!(s.strip_prefix("goodbye"), None);
3648		assert_eq!(s.strip_prefix("hello world!"), None);
3649	}
3650
3651	#[test]
3652	fn test_strip_suffix_none() {
3653		let s = Str::new("hello world");
3654		assert_eq!(s.strip_suffix("goodbye"), None);
3655		assert_eq!(s.strip_suffix("!hello world"), None);
3656	}
3657
3658	#[test]
3659	fn test_slice_ref_inline() {
3660		let text = "hello world";
3661		let s = Str::new(text);
3662		assert!(!s.is_spilled());
3663
3664		let subset = &text[6..11]; // "world"
3665		let sliced = s.slice_ref(subset);
3666		assert_eq!(sliced.as_str(), "world");
3667		assert!(!sliced.is_spilled()); // Should still be inline
3668	}
3669
3670	#[test]
3671	fn test_trim_end_zero_copy_heap() {
3672		let text = "hello world hello world hello   ";
3673		let s = Str::new(text);
3674		assert!(s.is_spilled());
3675
3676		let trimmed = s.trim_end();
3677		assert_eq!(trimmed.as_str(), "hello world hello world hello");
3678		assert!(trimmed.is_spilled());
3679	}
3680
3681	#[test]
3682	fn test_split_iterator_complete() {
3683		let s = Str::new("a,b,c,d,e");
3684		let parts: Vec<_> = s.split(",").collect();
3685		assert_eq!(parts.len(), 5);
3686		assert_eq!(parts[0], "a");
3687		assert_eq!(parts[1], "b");
3688		assert_eq!(parts[4], "e");
3689
3690		// Multiple separators
3691		let s2 = Str::new("a,,b");
3692		let parts2: Vec<_> = s2.split(",").collect();
3693		assert_eq!(parts2.len(), 3);
3694		assert_eq!(parts2[1], ""); // Empty between ,,
3695	}
3696
3697	#[test]
3698	fn test_split_no_separator() {
3699		let s = Str::new("hello");
3700		let parts: Vec<_> = s.split(",").collect();
3701		assert_eq!(parts.len(), 1);
3702		assert_eq!(parts[0], "hello");
3703	}
3704
3705	// ============================
3706	// Uniqueness & Sharing Tests
3707	// ============================
3708
3709	#[test]
3710	fn test_is_unique_inline() {
3711		let s = Str::new("hello");
3712		assert!(s.is_unique()); // Inline always unique
3713	}
3714
3715	#[test]
3716	fn test_is_unique_heap_unshared() {
3717		let s = Str::new("hello world hello world!!");
3718		assert!(s.is_unique()); // Newly created heap string is unique
3719	}
3720
3721	#[test]
3722	fn test_is_unique_heap_shared() {
3723		let s1 = Str::new("hello world hello world!!");
3724		let s2 = s1.clone();
3725
3726		assert!(!s1.is_unique()); // Now shared
3727		assert!(!s2.is_unique());
3728	}
3729
3730	#[test]
3731	fn test_into_ascii_uppercase_leaves_shared_clone_untouched() {
3732		let s1 = Str::new("hello world hello world!!");
3733		let s2 = s1.clone();
3734
3735		// Shared storage: the conversion must copy, not mutate in place.
3736		let upper = s1.into_ascii_uppercase();
3737
3738		assert_eq!(upper.as_str(), "HELLO WORLD HELLO WORLD!!");
3739		assert_eq!(s2.as_str(), "hello world hello world!!"); // Unchanged
3740	}
3741
3742	#[test]
3743	fn test_promote_inline_to_heap() {
3744		let mut s = Str::new("hello");
3745		assert!(!s.is_spilled());
3746
3747		let heap_str = s.promote();
3748		assert_eq!(&**heap_str, "hello");
3749		assert!(s.is_spilled());
3750	}
3751
3752	// ============================
3753	// Conversion Tests
3754	// ============================
3755
3756	#[test]
3757	fn test_from_arc_str() {
3758		let arc: std::sync::Arc<str> = "hello world hello world".into();
3759		let s = Str::from(arc);
3760		assert!(s.is_spilled());
3761		assert_eq!(s.as_str(), "hello world hello world");
3762	}
3763
3764	#[test]
3765	fn test_from_box_str() {
3766		let boxed: Box<str> = "hello world".into();
3767		let s = Str::from(boxed);
3768		assert_eq!(s.as_str(), "hello world");
3769	}
3770
3771	#[test]
3772	fn test_from_cow_borrowed() {
3773		let cow = std::borrow::Cow::Borrowed("hello");
3774		let s = Str::from(cow);
3775		assert_eq!(s.as_str(), "hello");
3776	}
3777
3778	#[test]
3779	fn test_from_cow_owned() {
3780		let cow = std::borrow::Cow::<str>::Owned(String::from("hello world hello world"));
3781		let s = Str::from(cow);
3782		assert_eq!(s.as_str(), "hello world hello world");
3783	}
3784
3785	#[test]
3786	fn test_into_string() {
3787		let s = Str::new("hello world");
3788		let string: String = s.into();
3789		assert_eq!(string, "hello world");
3790	}
3791
3792	#[test]
3793	fn test_into_bytes() {
3794		let s = Str::new("hello world hello world");
3795		let bytes: bytes::Bytes = s.into();
3796		assert_eq!(&bytes[..], b"hello world hello world");
3797	}
3798
3799	#[test]
3800	fn test_into_bytes_inline() {
3801		let s = Str::new("hello");
3802		let bytes: bytes::Bytes = s.into();
3803		assert_eq!(&bytes[..], b"hello");
3804	}
3805
3806	#[test]
3807	fn test_from_iterator_char() {
3808		let chars = vec!['h', 'e', 'l', 'l', 'o'];
3809		let s: Str = chars.into_iter().collect();
3810		assert_eq!(s.as_str(), "hello");
3811	}
3812
3813	#[test]
3814	fn test_from_iterator_str_ref() {
3815		let strs = vec!["hello", " ", "world"];
3816		let s: Str = strs.into_iter().collect();
3817		assert_eq!(s.as_str(), "hello world");
3818	}
3819
3820	#[test]
3821	fn test_from_iterator_string() {
3822		let strings = vec![String::from("hello"), String::from(" "), String::from("world")];
3823		let s: Str = strings.into_iter().collect();
3824		assert_eq!(s.as_str(), "hello world");
3825	}
3826
3827	#[test]
3828	fn test_from_iterator_triggers_heap() {
3829		let s: Str = "123456789012345678901234".chars().collect();
3830		assert!(s.is_spilled());
3831		assert_eq!(s.as_str(), "123456789012345678901234");
3832	}
3833
3834	// ============================
3835	// StrExt Tests
3836	// ============================
3837
3838	#[test]
3839	fn test_to_ascii_lowercase_str() {
3840		let s = "HELLO WORLD";
3841		let lower = s.to_ascii_lowercase_str();
3842		assert_eq!(lower.as_str(), "hello world");
3843		assert!(!lower.is_spilled());
3844
3845		let long = "HELLO WORLD HELLO WORLD!!";
3846		let lower_long = long.to_ascii_lowercase_str();
3847		assert_eq!(lower_long.as_str(), "hello world hello world!!");
3848		assert!(lower_long.is_spilled());
3849	}
3850
3851	#[test]
3852	fn test_to_ascii_uppercase_str() {
3853		let s = "hello world";
3854		let upper = s.to_ascii_uppercase_str();
3855		assert_eq!(upper.as_str(), "HELLO WORLD");
3856
3857		let already_upper = "HELLO";
3858		let upper2 = already_upper.to_ascii_uppercase_str();
3859		assert_eq!(upper2.as_str(), "HELLO");
3860	}
3861
3862	#[test]
3863	fn test_into_ascii_lowercase() {
3864		let s = Str::new("HELLO");
3865		let lower = s.into_ascii_lowercase();
3866		assert_eq!(lower.as_str(), "hello");
3867	}
3868
3869	#[test]
3870	fn test_into_ascii_uppercase() {
3871		let s = Str::new("hello");
3872		let upper = s.into_ascii_uppercase();
3873		assert_eq!(upper.as_str(), "HELLO");
3874	}
3875
3876	// ============================
3877	// Macro Tests
3878	// ============================
3879
3880	#[test]
3881	fn test_fmts_basic() {
3882		let s = fmts!("hello {}", "world");
3883		assert_eq!(s.as_str(), "hello world");
3884	}
3885
3886	#[test]
3887	fn test_fmts_numbers() {
3888		let s = fmts!("count: {}, pi: {:.2}", 42, std::f64::consts::PI);
3889		assert_eq!(s.as_str(), "count: 42, pi: 3.14");
3890	}
3891
3892	#[test]
3893	fn test_fmts_no_args() {
3894		let s = fmts!("static text");
3895		assert_eq!(s.as_str(), "static text");
3896	}
3897
3898	#[test]
3899	fn test_fmts_mut_basic() {
3900		let mut s = fmts_mut!("hello {}", "world");
3901		assert_eq!(s.as_str(), "hello world");
3902		s.push('!');
3903		assert_eq!(s.as_str(), "hello world!");
3904	}
3905
3906	#[test]
3907	fn test_fmts_heap_allocation() {
3908		let s = fmts!("{}", "123456789012345678901234");
3909		assert!(s.is_spilled());
3910		assert_eq!(s.as_str(), "123456789012345678901234");
3911	}
3912
3913	// ============================
3914	// Static String Tests
3915	// ============================
3916
3917	#[test]
3918	fn test_new_static() {
3919		const STATIC: &str = "hello world hello world";
3920		let s = Str::new_static(STATIC);
3921
3922		// Static strings always use heap representation (never inline)
3923		assert!(s.is_spilled());
3924		assert_eq!(s.as_str(), STATIC);
3925
3926		// Even short strings
3927		const SHORT: &str = "hi";
3928		let s2 = Str::new_static(SHORT);
3929		assert!(s2.is_spilled()); // Still heap due to static
3930	}
3931
3932	// ============================
3933	// Serde Tests
3934	// ============================
3935
3936	#[test]
3937	fn test_str_serde_roundtrip() {
3938		let s = Str::new("hello world");
3939		let json = json::to_string(&s).unwrap();
3940		assert_eq!(json, r#""hello world""#);
3941
3942		let deserialized: Str = json::from_str(&json).unwrap();
3943		assert_eq!(deserialized.as_str(), "hello world");
3944	}
3945
3946	#[test]
3947	fn test_str_serde_empty() {
3948		let s = Str::new("");
3949		let json = json::to_string(&s).unwrap();
3950		assert_eq!(json, r#""""#);
3951
3952		let deserialized: Str = json::from_str(&json).unwrap();
3953		assert!(deserialized.is_empty());
3954	}
3955
3956	#[test]
3957	fn test_str_serde_multibyte() {
3958		let s = Str::new("δΈ–η•Œ 🌍");
3959		let json = json::to_string(&s).unwrap();
3960
3961		let deserialized: Str = json::from_str(&json).unwrap();
3962		assert_eq!(deserialized.as_str(), "δΈ–η•Œ 🌍");
3963	}
3964
3965	// ============================
3966	// Edge Cases
3967	// ============================
3968
3969	#[test]
3970	fn test_clone_inline() {
3971		let s1 = Str::new("hello");
3972		let s2 = s1.clone();
3973		assert_eq!(s1, s2);
3974		assert!(!s1.is_spilled());
3975		assert!(!s2.is_spilled());
3976	}
3977
3978	#[test]
3979	fn test_clone_heap() {
3980		let s1 = Str::new("hello world hello world!!");
3981		let s2 = s1.clone();
3982		assert_eq!(s1, s2);
3983
3984		// Should share same backing
3985		assert!(!s1.is_unique());
3986		assert!(!s2.is_unique());
3987	}
3988
3989	#[test]
3990	fn test_default_str() {
3991		let s = Str::default();
3992		assert!(s.is_empty());
3993		assert!(!s.is_spilled());
3994	}
3995
3996	#[test]
3997	fn test_default_strmut() {
3998		let m = StrMut::default();
3999		assert!(m.is_empty());
4000		assert!(!m.is_spilled());
4001	}
4002
4003	#[test]
4004	fn test_with_capacity_inline() {
4005		let m = StrMut::with_capacity(10);
4006		assert!(!m.is_spilled());
4007		assert!(m.is_empty());
4008	}
4009
4010	#[test]
4011	fn test_with_capacity_heap() {
4012		let m = StrMut::with_capacity(100);
4013		assert!(m.is_spilled());
4014		assert!(m.is_empty());
4015	}
4016
4017	#[test]
4018	fn test_freeze_inline() {
4019		let m = StrMut::new("hello");
4020		let s = m.freeze();
4021		assert_eq!(s.as_str(), "hello");
4022		assert!(!s.is_spilled());
4023	}
4024
4025	#[test]
4026	fn test_freeze_heap() {
4027		let m = StrMut::new("hello world hello world!!");
4028		let s = m.freeze();
4029		assert_eq!(s.as_str(), "hello world hello world!!");
4030		assert!(s.is_spilled());
4031	}
4032
4033	#[test]
4034	fn test_extend_empty_iterator() {
4035		let mut m = StrMut::new("hello");
4036		let empty: Vec<&str> = vec![];
4037		m.extend(empty);
4038		assert_eq!(m.as_str(), "hello");
4039	}
4040
4041	#[test]
4042	fn test_equality_different_repr() {
4043		// Same content, different representations
4044		let inline = Str::new("hello");
4045		let heap = Str::new("hello world hello world!!").slice(0..5);
4046
4047		assert_eq!(inline, heap);
4048		assert!(!inline.is_spilled());
4049		assert!(heap.is_spilled());
4050	}
4051
4052	#[test]
4053	fn test_ordering() {
4054		let a = Str::new("apple");
4055		let b = Str::new("banana");
4056		let c = Str::new("cherry");
4057
4058		assert!(a < b);
4059		assert!(b < c);
4060		assert!(a < c);
4061		assert!((b >= a));
4062	}
4063
4064	#[test]
4065	fn test_hash_consistency() {
4066		use std::{
4067			collections::hash_map::DefaultHasher,
4068			hash::{Hash, Hasher},
4069		};
4070
4071		let s1 = Str::new("hello world");
4072		let s2 = Str::new("hello world hello world").slice(0..11);
4073
4074		let mut h1 = DefaultHasher::new();
4075		s1.hash(&mut h1);
4076
4077		let mut h2 = DefaultHasher::new();
4078		s2.hash(&mut h2);
4079
4080		assert_eq!(h1.finish(), h2.finish());
4081	}
4082
4083	#[test]
4084	fn test_as_bytes() {
4085		let s = Str::new("hello 🌍");
4086		let bytes = s.as_bytes();
4087		assert_eq!(bytes, "hello 🌍".as_bytes());
4088	}
4089
4090	#[test]
4091	fn test_insert_at_end() {
4092		let mut m = StrMut::new("hello");
4093		m.insert(5, " world");
4094		assert_eq!(m.as_str(), "hello world");
4095	}
4096
4097	#[test]
4098	fn test_insert_at_start() {
4099		let mut m = StrMut::new("world");
4100		m.insert(0, "hello ");
4101		assert_eq!(m.as_str(), "hello world");
4102	}
4103
4104	#[test]
4105	fn test_truncate_noop() {
4106		let mut s = Str::new("hello");
4107		s.truncate(100); // Greater than length
4108		assert_eq!(s.as_str(), "hello");
4109
4110		s.truncate(5); // Exact length
4111		assert_eq!(s.as_str(), "hello");
4112	}
4113
4114	#[test]
4115	fn test_truncate_mut_noop() {
4116		let mut m = StrMut::new("hello");
4117		m.truncate(100);
4118		assert_eq!(m.as_str(), "hello");
4119	}
4120
4121	#[test]
4122	fn test_deref_coercion() {
4123		let s = Str::new("hello");
4124		let len = s.len(); // Should work via Deref
4125		assert_eq!(len, 5);
4126
4127		// Can pass to function expecting &str
4128		fn takes_str(s: &str) -> usize {
4129			s.len()
4130		}
4131		assert_eq!(takes_str(&s), 5);
4132	}
4133
4134	#[test]
4135	fn test_borrow_trait() {
4136		use std::borrow::Borrow;
4137
4138		let s = Str::new("hello");
4139		let borrowed: &str = s.borrow();
4140		assert_eq!(borrowed, "hello");
4141	}
4142
4143	#[test]
4144	fn test_as_ref_os_str() {
4145		let s = Str::new("hello");
4146		let os_str: &std::ffi::OsStr = s.as_ref();
4147		assert_eq!(os_str, "hello");
4148	}
4149
4150	#[test]
4151	fn test_as_ref_path() {
4152		let s = Str::new("/tmp/file.txt");
4153		let path: &std::path::Path = s.as_ref();
4154		assert_eq!(path.to_str().unwrap(), "/tmp/file.txt");
4155	}
4156
4157	#[test]
4158	fn test_partial_eq_str() {
4159		let s = Str::new("hello");
4160		assert_eq!(s, "hello");
4161		assert_eq!("hello", s);
4162		assert_ne!(s, "world");
4163	}
4164
4165	#[test]
4166	fn test_partial_eq_string() {
4167		let s = Str::new("hello");
4168		let string = String::from("hello");
4169		assert_eq!(s, string);
4170		assert_eq!(string, s);
4171	}
4172
4173	#[test]
4174	fn test_strmut_deref_mut() {
4175		let mut m = StrMut::new("hello");
4176		let str_mut: &mut str = &mut m;
4177		str_mut.make_ascii_uppercase();
4178		assert_eq!(m.as_str(), "HELLO");
4179	}
4180
4181	#[test]
4182	fn test_from_str_parse() {
4183		let s: Str = "hello world".parse().unwrap();
4184		assert_eq!(s.as_str(), "hello world");
4185	}
4186
4187	#[test]
4188	fn test_into_str_trait() {
4189		use super::IntoStr;
4190
4191		let s: Str = "hello".into_str();
4192		assert_eq!(s.as_str(), "hello");
4193
4194		let num: i32 = 42;
4195		let s2 = (&num).to_str();
4196		assert_eq!(s2.as_str(), "42");
4197	}
4198
4199	#[test]
4200	fn test_write_trait() {
4201		use std::fmt::Write;
4202
4203		let mut m = StrMut::new("hello");
4204		write!(&mut m, " {}", 42).unwrap();
4205		assert_eq!(m.as_str(), "hello 42");
4206	}
4207
4208	#[test]
4209	fn test_display_format() {
4210		let s = Str::new("hello");
4211		let formatted = format!("{s}");
4212		assert_eq!(formatted, "hello");
4213	}
4214
4215	#[test]
4216	fn test_debug_format() {
4217		let s = Str::new("hello");
4218		let formatted = format!("{s:?}");
4219		assert_eq!(formatted, "\"hello\"");
4220	}
4221
4222	#[test]
4223	fn test_slice_heap_zero_copy() {
4224		let s = Str::new("hello world hello world!!");
4225		let sliced = s.slice(6..11);
4226		assert_eq!(sliced.as_str(), "world");
4227		assert!(sliced.is_spilled());
4228	}
4229
4230	#[test]
4231	fn test_slice_inline_creates_inline() {
4232		let s = Str::new("hello world");
4233		let sliced = s.slice(0..5);
4234		assert_eq!(sliced.as_str(), "hello");
4235		assert!(!sliced.is_spilled());
4236	}
4237
4238	#[test]
4239	fn test_reserve_heap_noop() {
4240		let mut m = StrMut::new("hello world hello world!!");
4241		assert!(m.is_spilled());
4242
4243		let initial_len = m.len();
4244		m.reserve(10);
4245
4246		assert_eq!(m.len(), initial_len);
4247		assert_eq!(m.as_str(), "hello world hello world!!");
4248	}
4249
4250	#[test]
4251	fn test_push_empty_string() {
4252		let mut m = StrMut::new("hello");
4253		m.push_str("");
4254		assert_eq!(m.as_str(), "hello");
4255	}
4256
4257	#[test]
4258	fn test_split_empty_separator() {
4259		let s = Str::new("hello");
4260		let parts = s.split("").filter(|s| !s.is_empty()).count();
4261		assert_eq!(parts, 5);
4262	}
4263
4264	#[test]
4265	fn test_from_bytes_mut() {
4266		let bytes_mut = bytes::BytesMut::from("hello world hello world");
4267		let result = StrMut::from_utf8_owned(bytes_mut);
4268		assert!(result.is_ok());
4269		let m = result.unwrap();
4270		assert_eq!(m.as_str(), "hello world hello world");
4271		assert!(m.is_spilled());
4272	}
4273
4274	#[test]
4275	fn test_into_bytes_mut() {
4276		let m = StrMut::new("hello world hello world");
4277		let bytes_mut: bytes::BytesMut = m.into();
4278		assert_eq!(&bytes_mut[..], b"hello world hello world");
4279	}
4280
4281	#[test]
4282	fn test_str_to_str() {
4283		let s = Str::new("hello");
4284		let str_ref: bytes_utils::Str = s.into();
4285		assert_eq!(&*str_ref, "hello");
4286	}
4287
4288	#[test]
4289	fn test_strmut_to_strmut() {
4290		let m = StrMut::new("hello world hello world");
4291		let str_mut: bytes_utils::StrMut = m.into();
4292		assert_eq!(&*str_mut, "hello world hello world");
4293	}
4294}