compose_library/foundations/
str.rs

1use crate::Iter;
2use compose_library::diag::bail;
3use compose_library::repr::Repr;
4use compose_library::vm::Vm;
5use compose_library::{IterValue, StringIterator, Value};
6use compose_macros::func;
7use compose_macros::{cast, scope, ty};
8use ecow::EcoString;
9use std::fmt;
10use std::ops::Add;
11
12#[derive(Debug, Clone, PartialEq, Eq, Hash)]
13#[ty(scope, cast, name = "String")]
14pub struct Str(pub EcoString);
15
16impl Add for &Str {
17    type Output = Str;
18
19    fn add(self, rhs: Self) -> Self::Output {
20        let mut l = self.0.clone();
21        l.push_str(&rhs.0);
22        Str(l)
23    }
24}
25
26#[scope]
27impl Str {
28    #[func]
29    pub fn chars(self, vm: &mut dyn Vm) -> IterValue {
30        IterValue::new(Iter::String(StringIterator::new(self.0)), vm)
31    }
32
33    #[func]
34    pub fn len(&self) -> usize {
35        self.0.len()
36    }
37
38    #[func]
39    pub fn is_empty(&self) -> bool {
40        self.0.is_empty()
41    }
42}
43
44impl Repr for Str {
45    fn repr(&self, _vm: &dyn Vm) -> EcoString {
46        self.0.clone()
47    }
48}
49
50impl fmt::Display for Str {
51    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52        write!(f, "{}", self.0)
53    }
54}
55
56impl From<EcoString> for Str {
57    fn from(s: EcoString) -> Self {
58        Str(s)
59    }
60}
61
62impl From<String> for Str {
63    fn from(value: String) -> Self {
64        Str(value.into())
65    }
66}
67
68impl From<&str> for Str {
69    fn from(s: &str) -> Self {
70        Str(s.into())
71    }
72}
73
74impl From<Str> for String {
75    fn from(s: Str) -> Self {
76        s.0.into()
77    }
78}
79
80impl From<Str> for EcoString {
81    fn from(s: Str) -> Self {
82        s.0
83    }
84}
85
86cast! {
87    &str,
88    self => Value::Str(self.into()),
89}
90
91cast! {
92    EcoString,
93    self => Value::Str(self.into()),
94    v: Str => v.into()
95}
96
97cast! {
98    char,
99    self => Value::Str(EcoString::from(self).into()),
100    v: Str => {
101        let mut chars = v.0.chars();
102        match (chars.next(), chars.next()) {
103            (Some(_), Some(_)) => bail!("cannot convert a string with more than one character to char: {}", v.0),
104            (Some(c), None) => c,
105            (None, _) => bail!("cannot convert empty string to char"),
106        }
107    }
108}