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
11#[cfg(not(feature = "std"))]
12use alloc::string::String;
13
14use crate::dynamic::{DynamicVec, InlineVec};
15
16#[macro_export]
22macro_rules! eco_format {
23 ($($tts:tt)*) => {{
24 use ::std::fmt::Write;
25 let mut s = $crate::EcoString::new();
26 ::std::write!(s, $($tts)*).unwrap();
27 s
28 }};
29}
30
31#[derive(Clone)]
64pub struct EcoString(DynamicVec);
65
66impl EcoString {
67 pub const INLINE_LIMIT: usize = crate::dynamic::LIMIT;
75
76 #[inline]
78 pub const fn new() -> Self {
79 Self(DynamicVec::new())
80 }
81
82 #[inline]
87 pub const fn inline(string: &str) -> Self {
88 let Ok(inline) = InlineVec::from_slice(string.as_bytes()) else {
89 exceeded_inline_capacity();
90 };
91 Self(DynamicVec::from_inline(inline))
92 }
93
94 #[inline]
96 pub fn with_capacity(capacity: usize) -> Self {
97 Self(DynamicVec::with_capacity(capacity))
98 }
99
100 #[inline]
102 fn from_str(string: &str) -> Self {
103 Self(DynamicVec::from_slice(string.as_bytes()))
104 }
105
106 #[inline]
108 pub fn is_empty(&self) -> bool {
109 self.len() == 0
110 }
111
112 #[inline]
114 pub fn len(&self) -> usize {
115 self.0.len()
116 }
117
118 #[inline]
120 pub fn as_str(&self) -> &str {
121 unsafe { core::str::from_utf8_unchecked(self.0.as_slice()) }
127 }
128
129 #[inline]
133 pub fn make_mut(&mut self) -> &mut str {
134 unsafe { core::str::from_utf8_unchecked_mut(self.0.make_mut()) }
140 }
141
142 #[inline]
144 pub fn push(&mut self, c: char) {
145 if c.len_utf8() == 1 {
146 self.0.push(c as u8);
147 } else {
148 self.push_str(c.encode_utf8(&mut [0; 4]));
149 }
150 }
151
152 pub fn push_str(&mut self, string: &str) {
154 self.0.extend_from_slice(string.as_bytes());
155 }
156
157 #[inline]
159 pub fn pop(&mut self) -> Option<char> {
160 let slice = self.as_str();
161 let c = slice.chars().next_back()?;
162 self.0.truncate(slice.len() - c.len_utf8());
163 Some(c)
164 }
165
166 #[inline]
168 pub fn clear(&mut self) {
169 self.0.clear();
170 }
171
172 #[inline]
179 pub fn truncate(&mut self, new_len: usize) {
180 if new_len <= self.len() {
181 assert!(self.is_char_boundary(new_len));
182 self.0.truncate(new_len);
183 }
184 }
185
186 pub fn replace(&self, pat: &str, to: &str) -> Self {
192 self.replacen(pat, to, usize::MAX)
193 }
194
195 pub fn replacen(&self, pat: &str, to: &str, count: usize) -> Self {
201 let mut result = Self::new();
203 let mut last_end = 0;
204 for (start, part) in self.match_indices(pat).take(count) {
205 result.push_str(unsafe { self.get_unchecked(last_end..start) });
207 result.push_str(to);
208 last_end = start + part.len();
209 }
210 result.push_str(unsafe { self.get_unchecked(last_end..self.len()) });
212 result
213 }
214
215 pub fn to_lowercase(&self) -> Self {
217 let str = self.as_str();
218 let mut lower = Self::with_capacity(str.len());
219 for c in str.chars() {
220 if c == 'Σ' {
222 return str.to_lowercase().into();
223 }
224 for v in c.to_lowercase() {
225 lower.push(v);
226 }
227 }
228 lower
229 }
230
231 pub fn to_uppercase(&self) -> Self {
233 let str = self.as_str();
234 let mut upper = Self::with_capacity(str.len());
235 for c in str.chars() {
236 for v in c.to_uppercase() {
237 upper.push(v);
238 }
239 }
240 upper
241 }
242
243 pub fn to_ascii_lowercase(&self) -> Self {
246 let mut s = self.clone();
247 s.make_mut().make_ascii_lowercase();
248 s
249 }
250
251 pub fn to_ascii_uppercase(&self) -> Self {
254 let mut s = self.clone();
255 s.make_mut().make_ascii_uppercase();
256 s
257 }
258
259 pub fn repeat(&self, n: usize) -> Self {
261 let slice = self.as_bytes();
262 let capacity = slice.len().saturating_mul(n);
263 let mut vec = DynamicVec::with_capacity(capacity);
264 for _ in 0..n {
265 vec.extend_from_slice(slice);
266 }
267 Self(vec)
268 }
269}
270
271impl Deref for EcoString {
272 type Target = str;
273
274 #[inline]
275 fn deref(&self) -> &str {
276 self.as_str()
277 }
278}
279
280impl Default for EcoString {
281 #[inline]
282 fn default() -> Self {
283 Self::new()
284 }
285}
286
287impl Debug for EcoString {
288 #[inline]
289 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
290 Debug::fmt(self.as_str(), f)
291 }
292}
293
294impl Display for EcoString {
295 #[inline]
296 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
297 Display::fmt(self.as_str(), f)
298 }
299}
300
301impl Eq for EcoString {}
302
303impl PartialEq for EcoString {
304 #[inline]
305 fn eq(&self, other: &Self) -> bool {
306 self.as_str().eq(other.as_str())
307 }
308}
309
310impl PartialEq<str> for EcoString {
311 #[inline]
312 fn eq(&self, other: &str) -> bool {
313 self.as_str().eq(other)
314 }
315}
316
317impl PartialEq<&str> for EcoString {
318 #[inline]
319 fn eq(&self, other: &&str) -> bool {
320 self.as_str().eq(*other)
321 }
322}
323
324impl PartialEq<String> for EcoString {
325 #[inline]
326 fn eq(&self, other: &String) -> bool {
327 self.as_str().eq(other)
328 }
329}
330
331impl PartialEq<EcoString> for str {
332 #[inline]
333 fn eq(&self, other: &EcoString) -> bool {
334 self.eq(other.as_str())
335 }
336}
337
338impl PartialEq<EcoString> for &str {
339 #[inline]
340 fn eq(&self, other: &EcoString) -> bool {
341 (*self).eq(other.as_str())
342 }
343}
344
345impl PartialEq<EcoString> for String {
346 #[inline]
347 fn eq(&self, other: &EcoString) -> bool {
348 self.eq(other.as_str())
349 }
350}
351
352impl Ord for EcoString {
353 #[inline]
354 fn cmp(&self, other: &Self) -> Ordering {
355 self.as_str().cmp(other.as_str())
356 }
357}
358
359impl PartialOrd for EcoString {
360 #[inline]
361 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
362 Some(self.cmp(other))
363 }
364}
365
366impl Hash for EcoString {
367 #[inline]
368 fn hash<H: Hasher>(&self, state: &mut H) {
369 self.as_str().hash(state);
370 }
371}
372
373impl Write for EcoString {
374 #[inline]
375 fn write_str(&mut self, s: &str) -> fmt::Result {
376 self.push_str(s);
377 Ok(())
378 }
379
380 #[inline]
381 fn write_char(&mut self, c: char) -> fmt::Result {
382 self.push(c);
383 Ok(())
384 }
385}
386
387impl Add for EcoString {
388 type Output = Self;
389
390 #[inline]
391 fn add(mut self, rhs: Self) -> Self::Output {
392 self += rhs;
393 self
394 }
395}
396
397impl AddAssign for EcoString {
398 #[inline]
399 fn add_assign(&mut self, rhs: Self) {
400 self.push_str(rhs.as_str());
401 }
402}
403
404impl Add<&str> for EcoString {
405 type Output = Self;
406
407 #[inline]
408 fn add(mut self, rhs: &str) -> Self::Output {
409 self += rhs;
410 self
411 }
412}
413
414impl AddAssign<&str> for EcoString {
415 #[inline]
416 fn add_assign(&mut self, rhs: &str) {
417 self.push_str(rhs);
418 }
419}
420
421impl AsRef<str> for EcoString {
422 #[inline]
423 fn as_ref(&self) -> &str {
424 self
425 }
426}
427
428impl Borrow<str> for EcoString {
429 #[inline]
430 fn borrow(&self) -> &str {
431 self
432 }
433}
434
435impl From<char> for EcoString {
436 #[inline]
437 fn from(c: char) -> Self {
438 Self::inline(c.encode_utf8(&mut [0; 4]))
439 }
440}
441
442impl From<&str> for EcoString {
443 #[inline]
444 fn from(s: &str) -> Self {
445 Self::from_str(s)
446 }
447}
448
449impl From<String> for EcoString {
450 #[inline]
453 fn from(s: String) -> Self {
454 Self::from_str(&s)
455 }
456}
457
458impl From<&String> for EcoString {
459 #[inline]
460 fn from(s: &String) -> Self {
461 Self::from_str(s.as_str())
462 }
463}
464
465impl From<&EcoString> for EcoString {
466 #[inline]
467 fn from(s: &EcoString) -> Self {
468 s.clone()
469 }
470}
471
472impl From<Cow<'_, str>> for EcoString {
473 #[inline]
474 fn from(s: Cow<str>) -> Self {
475 Self::from_str(&s)
476 }
477}
478
479impl FromIterator<char> for EcoString {
480 #[inline]
481 fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
482 let mut s = Self::new();
483 for c in iter {
484 s.push(c);
485 }
486 s
487 }
488}
489
490impl FromIterator<Self> for EcoString {
491 #[inline]
492 fn from_iter<T: IntoIterator<Item = Self>>(iter: T) -> Self {
493 let mut s = Self::new();
494 for piece in iter {
495 s.push_str(&piece);
496 }
497 s
498 }
499}
500
501impl Extend<char> for EcoString {
502 #[inline]
503 fn extend<T: IntoIterator<Item = char>>(&mut self, iter: T) {
504 for c in iter {
505 self.push(c);
506 }
507 }
508}
509
510impl From<EcoString> for String {
511 #[inline]
513 fn from(s: EcoString) -> Self {
514 s.as_str().into()
515 }
516}
517
518impl From<&EcoString> for String {
519 #[inline]
520 fn from(s: &EcoString) -> Self {
521 s.as_str().into()
522 }
523}
524
525impl FromStr for EcoString {
526 type Err = core::convert::Infallible;
527
528 #[inline]
529 fn from_str(s: &str) -> Result<Self, Self::Err> {
530 Ok(Self::from_str(s))
531 }
532}
533
534#[cold]
535const fn exceeded_inline_capacity() -> ! {
536 panic!("exceeded inline capacity");
537}
538
539#[cfg(feature = "serde")]
540mod serde {
541 use crate::EcoString;
542 use core::fmt;
543 use serde::de::{Deserializer, Error, Unexpected, Visitor};
544
545 impl serde::Serialize for EcoString {
546 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
547 where
548 S: serde::Serializer,
549 {
550 self.as_str().serialize(serializer)
551 }
552 }
553
554 impl<'de> serde::Deserialize<'de> for EcoString {
555 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
556 where
557 D: Deserializer<'de>,
558 {
559 struct EcoStringVisitor;
560
561 impl Visitor<'_> for EcoStringVisitor {
562 type Value = EcoString;
563
564 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
565 formatter.write_str("a string")
566 }
567
568 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
569 where
570 E: Error,
571 {
572 Ok(EcoString::from(v))
573 }
574
575 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
576 where
577 E: Error,
578 {
579 if let Ok(utf8) = core::str::from_utf8(v) {
580 return Ok(EcoString::from(utf8));
581 }
582 Err(Error::invalid_value(Unexpected::Bytes(v), &self))
583 }
584 }
585
586 deserializer.deserialize_str(EcoStringVisitor)
587 }
588 }
589}