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 pub fn replace(&self, pat: &str, to: &str) -> Self {
177 self.replacen(pat, to, usize::MAX)
178 }
179
180 pub fn replacen(&self, pat: &str, to: &str, count: usize) -> Self {
186 let mut result = Self::new();
188 let mut last_end = 0;
189 for (start, part) in self.match_indices(pat).take(count) {
190 result.push_str(unsafe { self.get_unchecked(last_end..start) });
192 result.push_str(to);
193 last_end = start + part.len();
194 }
195 result.push_str(unsafe { self.get_unchecked(last_end..self.len()) });
197 result
198 }
199
200 pub fn to_lowercase(&self) -> Self {
202 let str = self.as_str();
203 let mut lower = Self::with_capacity(str.len());
204 for c in str.chars() {
205 if c == 'Σ' {
207 return str.to_lowercase().into();
208 }
209 for v in c.to_lowercase() {
210 lower.push(v);
211 }
212 }
213 lower
214 }
215
216 pub fn to_uppercase(&self) -> Self {
218 let str = self.as_str();
219 let mut upper = Self::with_capacity(str.len());
220 for c in str.chars() {
221 for v in c.to_uppercase() {
222 upper.push(v);
223 }
224 }
225 upper
226 }
227
228 pub fn to_ascii_lowercase(&self) -> Self {
231 let mut s = self.clone();
232 s.make_mut().make_ascii_lowercase();
233 s
234 }
235
236 pub fn to_ascii_uppercase(&self) -> Self {
239 let mut s = self.clone();
240 s.make_mut().make_ascii_uppercase();
241 s
242 }
243
244 pub fn repeat(&self, n: usize) -> Self {
246 let slice = self.as_bytes();
247 let capacity = slice.len().saturating_mul(n);
248 let mut vec = DynamicVec::with_capacity(capacity);
249 for _ in 0..n {
250 vec.extend_from_slice(slice);
251 }
252 Self(vec)
253 }
254}
255
256impl Deref for EcoString {
257 type Target = str;
258
259 #[inline]
260 fn deref(&self) -> &str {
261 self.as_str()
262 }
263}
264
265impl Default for EcoString {
266 #[inline]
267 fn default() -> Self {
268 Self::new()
269 }
270}
271
272impl Debug for EcoString {
273 #[inline]
274 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
275 Debug::fmt(self.as_str(), f)
276 }
277}
278
279impl Display for EcoString {
280 #[inline]
281 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
282 Display::fmt(self.as_str(), f)
283 }
284}
285
286impl Eq for EcoString {}
287
288impl PartialEq for EcoString {
289 #[inline]
290 fn eq(&self, other: &Self) -> bool {
291 self.as_str().eq(other.as_str())
292 }
293}
294
295impl PartialEq<str> for EcoString {
296 #[inline]
297 fn eq(&self, other: &str) -> bool {
298 self.as_str().eq(other)
299 }
300}
301
302impl PartialEq<&str> for EcoString {
303 #[inline]
304 fn eq(&self, other: &&str) -> bool {
305 self.as_str().eq(*other)
306 }
307}
308
309impl PartialEq<String> for EcoString {
310 #[inline]
311 fn eq(&self, other: &String) -> bool {
312 self.as_str().eq(other)
313 }
314}
315
316impl PartialEq<EcoString> for str {
317 #[inline]
318 fn eq(&self, other: &EcoString) -> bool {
319 self.eq(other.as_str())
320 }
321}
322
323impl PartialEq<EcoString> for &str {
324 #[inline]
325 fn eq(&self, other: &EcoString) -> bool {
326 (*self).eq(other.as_str())
327 }
328}
329
330impl PartialEq<EcoString> for String {
331 #[inline]
332 fn eq(&self, other: &EcoString) -> bool {
333 self.eq(other.as_str())
334 }
335}
336
337impl Ord for EcoString {
338 #[inline]
339 fn cmp(&self, other: &Self) -> Ordering {
340 self.as_str().cmp(other.as_str())
341 }
342}
343
344impl PartialOrd for EcoString {
345 #[inline]
346 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
347 Some(self.cmp(other))
348 }
349}
350
351impl Hash for EcoString {
352 #[inline]
353 fn hash<H: Hasher>(&self, state: &mut H) {
354 self.as_str().hash(state);
355 }
356}
357
358impl Write for EcoString {
359 #[inline]
360 fn write_str(&mut self, s: &str) -> fmt::Result {
361 self.push_str(s);
362 Ok(())
363 }
364
365 #[inline]
366 fn write_char(&mut self, c: char) -> fmt::Result {
367 self.push(c);
368 Ok(())
369 }
370}
371
372impl Add for EcoString {
373 type Output = Self;
374
375 #[inline]
376 fn add(mut self, rhs: Self) -> Self::Output {
377 self += rhs;
378 self
379 }
380}
381
382impl AddAssign for EcoString {
383 #[inline]
384 fn add_assign(&mut self, rhs: Self) {
385 self.push_str(rhs.as_str());
386 }
387}
388
389impl Add<&str> for EcoString {
390 type Output = Self;
391
392 #[inline]
393 fn add(mut self, rhs: &str) -> Self::Output {
394 self += rhs;
395 self
396 }
397}
398
399impl AddAssign<&str> for EcoString {
400 #[inline]
401 fn add_assign(&mut self, rhs: &str) {
402 self.push_str(rhs);
403 }
404}
405
406impl AsRef<str> for EcoString {
407 #[inline]
408 fn as_ref(&self) -> &str {
409 self
410 }
411}
412
413impl Borrow<str> for EcoString {
414 #[inline]
415 fn borrow(&self) -> &str {
416 self
417 }
418}
419
420impl From<char> for EcoString {
421 #[inline]
422 fn from(c: char) -> Self {
423 Self::inline(c.encode_utf8(&mut [0; 4]))
424 }
425}
426
427impl From<&str> for EcoString {
428 #[inline]
429 fn from(s: &str) -> Self {
430 Self::from_str(s)
431 }
432}
433
434impl From<String> for EcoString {
435 #[inline]
438 fn from(s: String) -> Self {
439 Self::from_str(&s)
440 }
441}
442
443impl From<&String> for EcoString {
444 #[inline]
445 fn from(s: &String) -> Self {
446 Self::from_str(s.as_str())
447 }
448}
449
450impl From<&EcoString> for EcoString {
451 #[inline]
452 fn from(s: &EcoString) -> Self {
453 s.clone()
454 }
455}
456
457impl From<Cow<'_, str>> for EcoString {
458 #[inline]
459 fn from(s: Cow<str>) -> Self {
460 Self::from_str(&s)
461 }
462}
463
464impl FromIterator<char> for EcoString {
465 #[inline]
466 fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
467 let mut s = Self::new();
468 for c in iter {
469 s.push(c);
470 }
471 s
472 }
473}
474
475impl FromIterator<Self> for EcoString {
476 #[inline]
477 fn from_iter<T: IntoIterator<Item = Self>>(iter: T) -> Self {
478 let mut s = Self::new();
479 for piece in iter {
480 s.push_str(&piece);
481 }
482 s
483 }
484}
485
486impl Extend<char> for EcoString {
487 #[inline]
488 fn extend<T: IntoIterator<Item = char>>(&mut self, iter: T) {
489 for c in iter {
490 self.push(c);
491 }
492 }
493}
494
495impl From<EcoString> for String {
496 #[inline]
498 fn from(s: EcoString) -> Self {
499 s.as_str().into()
500 }
501}
502
503impl From<&EcoString> for String {
504 #[inline]
505 fn from(s: &EcoString) -> Self {
506 s.as_str().into()
507 }
508}
509
510#[cold]
511const fn exceeded_inline_capacity() -> ! {
512 panic!("exceeded inline capacity");
513}
514
515#[cfg(feature = "serde")]
516mod serde {
517 use crate::EcoString;
518 use core::fmt;
519 use serde::de::{Deserializer, Error, Unexpected, Visitor};
520
521 impl serde::Serialize for EcoString {
522 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
523 where
524 S: serde::Serializer,
525 {
526 self.as_str().serialize(serializer)
527 }
528 }
529
530 impl<'de> serde::Deserialize<'de> for EcoString {
531 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
532 where
533 D: Deserializer<'de>,
534 {
535 struct EcoStringVisitor;
536
537 impl<'a> Visitor<'a> for EcoStringVisitor {
538 type Value = EcoString;
539
540 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
541 formatter.write_str("a string")
542 }
543
544 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
545 where
546 E: Error,
547 {
548 Ok(EcoString::from(v))
549 }
550
551 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
552 where
553 E: Error,
554 {
555 if let Ok(utf8) = core::str::from_utf8(v) {
556 return Ok(EcoString::from(utf8));
557 }
558 Err(Error::invalid_value(Unexpected::Bytes(v), &self))
559 }
560 }
561
562 deserializer.deserialize_str(EcoStringVisitor)
563 }
564 }
565}