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