1use alloc::borrow::Cow;
4use core::borrow::Borrow;
5use core::cmp::Ordering;
6use core::fmt::{self, Debug, Display, Formatter, Write};
7use core::hash::{Hash, Hasher};
8use core::ops::{Add, AddAssign, Deref};
9use core::str::FromStr;
10#[cfg(feature = "std")]
11use std::ffi::OsStr;
12#[cfg(feature = "std")]
13use std::path::Path;
14
15#[cfg(not(feature = "std"))]
16use alloc::string::String;
17
18use crate::dynamic::{DynamicVec, InlineVec};
19
20#[macro_export]
26#[clippy::format_args]
27macro_rules! eco_format {
28 ($($tts:tt)*) => {{
29 use ::std::fmt::Write;
30 let mut s = $crate::EcoString::new();
31 ::std::write!(s, $($tts)*).unwrap();
32 s
33 }};
34}
35
36#[derive(Clone)]
69pub struct EcoString(DynamicVec);
70
71impl EcoString {
72 pub const INLINE_LIMIT: usize = crate::dynamic::LIMIT;
80
81 #[inline]
83 pub const fn new() -> Self {
84 Self(DynamicVec::new())
85 }
86
87 #[inline]
92 pub const fn inline(string: &str) -> Self {
93 let Ok(inline) = InlineVec::from_slice(string.as_bytes()) else {
94 exceeded_inline_capacity();
95 };
96 Self(DynamicVec::from_inline(inline))
97 }
98
99 #[inline]
101 pub fn with_capacity(capacity: usize) -> Self {
102 Self(DynamicVec::with_capacity(capacity))
103 }
104
105 #[inline]
107 fn from_str(string: &str) -> Self {
108 Self(DynamicVec::from_slice(string.as_bytes()))
109 }
110
111 #[inline]
113 pub fn is_empty(&self) -> bool {
114 self.len() == 0
115 }
116
117 #[inline]
119 pub fn len(&self) -> usize {
120 self.0.len()
121 }
122
123 #[inline]
125 pub fn as_str(&self) -> &str {
126 unsafe { core::str::from_utf8_unchecked(self.0.as_slice()) }
132 }
133
134 #[inline]
138 pub fn make_mut(&mut self) -> &mut str {
139 unsafe { core::str::from_utf8_unchecked_mut(self.0.make_mut()) }
145 }
146
147 #[inline]
149 pub fn push(&mut self, c: char) {
150 if c.len_utf8() == 1 {
151 self.0.push(c as u8);
152 } else {
153 self.push_str(c.encode_utf8(&mut [0; 4]));
154 }
155 }
156
157 pub fn push_str(&mut self, string: &str) {
159 self.0.extend_from_slice(string.as_bytes());
160 }
161
162 pub fn insert(&mut self, index: usize, c: char) {
164 self.insert_str(index, c.encode_utf8(&mut [0; 4]));
165 }
166
167 pub fn insert_str(&mut self, index: usize, string: &str) {
169 assert!(self.is_char_boundary(index));
170 self.0.insert_slice(index, string.as_bytes());
171 }
172
173 #[inline]
175 pub fn pop(&mut self) -> Option<char> {
176 let slice = self.as_str();
177 let c = slice.chars().next_back()?;
178 self.0.truncate(slice.len() - c.len_utf8());
179 Some(c)
180 }
181
182 #[inline]
184 pub fn clear(&mut self) {
185 self.0.clear();
186 }
187
188 #[inline]
195 pub fn truncate(&mut self, new_len: usize) {
196 if new_len <= self.len() {
197 assert!(self.is_char_boundary(new_len));
198 self.0.truncate(new_len);
199 }
200 }
201
202 pub fn remove(&mut self, index: usize) -> char {
204 assert!(self.is_char_boundary(index));
205 let char = self[index..].chars().next().unwrap();
206 self.0.remove_range(index..index + char.len_utf8());
207 char
208 }
209
210 pub fn replace(&self, pat: &str, to: &str) -> Self {
216 self.replacen(pat, to, usize::MAX)
217 }
218
219 pub fn replacen(&self, pat: &str, to: &str, count: usize) -> Self {
225 let mut result = Self::new();
227 let mut last_end = 0;
228 for (start, part) in self.match_indices(pat).take(count) {
229 result.push_str(unsafe { self.get_unchecked(last_end..start) });
231 result.push_str(to);
232 last_end = start + part.len();
233 }
234 result.push_str(unsafe { self.get_unchecked(last_end..self.len()) });
236 result
237 }
238
239 pub fn to_lowercase(&self) -> Self {
241 let str = self.as_str();
242 let mut lower = Self::with_capacity(str.len());
243 for c in str.chars() {
244 if c == 'Σ' {
246 return str.to_lowercase().into();
247 }
248 for v in c.to_lowercase() {
249 lower.push(v);
250 }
251 }
252 lower
253 }
254
255 pub fn to_uppercase(&self) -> Self {
257 let str = self.as_str();
258 let mut upper = Self::with_capacity(str.len());
259 for c in str.chars() {
260 for v in c.to_uppercase() {
261 upper.push(v);
262 }
263 }
264 upper
265 }
266
267 pub fn to_ascii_lowercase(&self) -> Self {
270 let mut s = self.clone();
271 s.make_mut().make_ascii_lowercase();
272 s
273 }
274
275 pub fn to_ascii_uppercase(&self) -> Self {
278 let mut s = self.clone();
279 s.make_mut().make_ascii_uppercase();
280 s
281 }
282
283 pub fn repeat(&self, n: usize) -> Self {
285 let slice = self.as_bytes();
286 let capacity = slice.len().saturating_mul(n);
287 let mut vec = DynamicVec::with_capacity(capacity);
288 for _ in 0..n {
289 vec.extend_from_slice(slice);
290 }
291 Self(vec)
292 }
293}
294
295impl Deref for EcoString {
296 type Target = str;
297
298 #[inline]
299 fn deref(&self) -> &str {
300 self.as_str()
301 }
302}
303
304impl Default for EcoString {
305 #[inline]
306 fn default() -> Self {
307 Self::new()
308 }
309}
310
311impl Debug for EcoString {
312 #[inline]
313 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
314 Debug::fmt(self.as_str(), f)
315 }
316}
317
318impl Display for EcoString {
319 #[inline]
320 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
321 Display::fmt(self.as_str(), f)
322 }
323}
324
325impl Eq for EcoString {}
326
327impl PartialEq for EcoString {
328 #[inline]
329 fn eq(&self, other: &Self) -> bool {
330 self.as_str().eq(other.as_str())
331 }
332}
333
334impl PartialEq<str> for EcoString {
335 #[inline]
336 fn eq(&self, other: &str) -> bool {
337 self.as_str().eq(other)
338 }
339}
340
341impl PartialEq<&str> for EcoString {
342 #[inline]
343 fn eq(&self, other: &&str) -> bool {
344 self.as_str().eq(*other)
345 }
346}
347
348impl PartialEq<String> for EcoString {
349 #[inline]
350 fn eq(&self, other: &String) -> bool {
351 self.as_str().eq(other)
352 }
353}
354
355impl PartialEq<EcoString> for str {
356 #[inline]
357 fn eq(&self, other: &EcoString) -> bool {
358 self.eq(other.as_str())
359 }
360}
361
362impl PartialEq<EcoString> for &str {
363 #[inline]
364 fn eq(&self, other: &EcoString) -> bool {
365 (*self).eq(other.as_str())
366 }
367}
368
369impl PartialEq<EcoString> for String {
370 #[inline]
371 fn eq(&self, other: &EcoString) -> bool {
372 self.eq(other.as_str())
373 }
374}
375
376impl Ord for EcoString {
377 #[inline]
378 fn cmp(&self, other: &Self) -> Ordering {
379 self.as_str().cmp(other.as_str())
380 }
381}
382
383impl PartialOrd for EcoString {
384 #[inline]
385 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
386 Some(self.cmp(other))
387 }
388}
389
390impl Hash for EcoString {
391 #[inline]
392 fn hash<H: Hasher>(&self, state: &mut H) {
393 self.as_str().hash(state);
394 }
395}
396
397impl Write for EcoString {
398 #[inline]
399 fn write_str(&mut self, s: &str) -> fmt::Result {
400 self.push_str(s);
401 Ok(())
402 }
403
404 #[inline]
405 fn write_char(&mut self, c: char) -> fmt::Result {
406 self.push(c);
407 Ok(())
408 }
409}
410
411impl Add for EcoString {
412 type Output = Self;
413
414 #[inline]
415 fn add(mut self, rhs: Self) -> Self::Output {
416 self += rhs;
417 self
418 }
419}
420
421impl AddAssign for EcoString {
422 #[inline]
423 fn add_assign(&mut self, rhs: Self) {
424 self.push_str(rhs.as_str());
425 }
426}
427
428impl Add<&str> for EcoString {
429 type Output = Self;
430
431 #[inline]
432 fn add(mut self, rhs: &str) -> Self::Output {
433 self += rhs;
434 self
435 }
436}
437
438impl AddAssign<&str> for EcoString {
439 #[inline]
440 fn add_assign(&mut self, rhs: &str) {
441 self.push_str(rhs);
442 }
443}
444
445impl AsRef<str> for EcoString {
446 #[inline]
447 fn as_ref(&self) -> &str {
448 self
449 }
450}
451
452impl Borrow<str> for EcoString {
453 #[inline]
454 fn borrow(&self) -> &str {
455 self
456 }
457}
458
459impl AsRef<[u8]> for EcoString {
460 #[inline]
461 fn as_ref(&self) -> &[u8] {
462 self.as_str().as_bytes()
463 }
464}
465
466#[cfg(feature = "std")]
467impl AsRef<OsStr> for EcoString {
468 #[inline]
469 fn as_ref(&self) -> &OsStr {
470 self.as_str().as_ref()
471 }
472}
473
474#[cfg(feature = "std")]
475impl AsRef<Path> for EcoString {
476 #[inline]
477 fn as_ref(&self) -> &Path {
478 self.as_str().as_ref()
479 }
480}
481
482impl From<char> for EcoString {
483 #[inline]
484 fn from(c: char) -> Self {
485 Self::inline(c.encode_utf8(&mut [0; 4]))
486 }
487}
488
489impl From<&str> for EcoString {
490 #[inline]
491 fn from(s: &str) -> Self {
492 Self::from_str(s)
493 }
494}
495
496impl From<String> for EcoString {
497 #[inline]
500 fn from(s: String) -> Self {
501 Self::from_str(&s)
502 }
503}
504
505impl From<&String> for EcoString {
506 #[inline]
507 fn from(s: &String) -> Self {
508 Self::from_str(s.as_str())
509 }
510}
511
512impl From<&EcoString> for EcoString {
513 #[inline]
514 fn from(s: &EcoString) -> Self {
515 s.clone()
516 }
517}
518
519impl From<Cow<'_, str>> for EcoString {
520 #[inline]
521 fn from(s: Cow<str>) -> Self {
522 Self::from_str(&s)
523 }
524}
525
526impl FromIterator<char> for EcoString {
527 #[inline]
528 fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
529 let mut s = Self::new();
530 for c in iter {
531 s.push(c);
532 }
533 s
534 }
535}
536
537impl<'a> FromIterator<&'a str> for EcoString {
538 #[inline]
539 fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
540 let mut buf = Self::new();
541 buf.extend(iter);
542 buf
543 }
544}
545
546impl FromIterator<Self> for EcoString {
547 #[inline]
548 fn from_iter<T: IntoIterator<Item = Self>>(iter: T) -> Self {
549 let mut s = Self::new();
550 for piece in iter {
551 s.push_str(&piece);
552 }
553 s
554 }
555}
556
557impl Extend<char> for EcoString {
558 #[inline]
559 fn extend<T: IntoIterator<Item = char>>(&mut self, iter: T) {
560 for c in iter {
561 self.push(c);
562 }
563 }
564}
565
566impl<'a> Extend<&'a str> for EcoString {
567 #[inline]
568 fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T) {
569 iter.into_iter().for_each(move |s| self.push_str(s));
570 }
571}
572
573impl From<EcoString> for String {
574 #[inline]
576 fn from(s: EcoString) -> Self {
577 s.as_str().into()
578 }
579}
580
581impl From<&EcoString> for String {
582 #[inline]
583 fn from(s: &EcoString) -> Self {
584 s.as_str().into()
585 }
586}
587
588impl FromStr for EcoString {
589 type Err = core::convert::Infallible;
590
591 #[inline]
592 fn from_str(s: &str) -> Result<Self, Self::Err> {
593 Ok(Self::from_str(s))
594 }
595}
596
597pub trait ToEcoString {
602 fn to_eco_string(&self) -> EcoString;
604}
605
606impl<T: Display + ?Sized> ToEcoString for T {
607 fn to_eco_string(&self) -> EcoString {
608 eco_format!("{self}")
609 }
610}
611
612#[cold]
613const fn exceeded_inline_capacity() -> ! {
614 panic!("exceeded inline capacity");
615}
616
617#[cfg(feature = "serde")]
618mod serde {
619 use crate::EcoString;
620 use core::fmt;
621 use serde::de::{Deserializer, Error, Unexpected, Visitor};
622
623 impl serde::Serialize for EcoString {
624 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
625 where
626 S: serde::Serializer,
627 {
628 self.as_str().serialize(serializer)
629 }
630 }
631
632 impl<'de> serde::Deserialize<'de> for EcoString {
633 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
634 where
635 D: Deserializer<'de>,
636 {
637 struct EcoStringVisitor;
638
639 impl Visitor<'_> for EcoStringVisitor {
640 type Value = EcoString;
641
642 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
643 formatter.write_str("a string")
644 }
645
646 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
647 where
648 E: Error,
649 {
650 Ok(EcoString::from(v))
651 }
652
653 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
654 where
655 E: Error,
656 {
657 if let Ok(utf8) = core::str::from_utf8(v) {
658 return Ok(EcoString::from(utf8));
659 }
660 Err(Error::invalid_value(Unexpected::Bytes(v), &self))
661 }
662 }
663
664 deserializer.deserialize_str(EcoStringVisitor)
665 }
666 }
667}