1#[derive(Debug, Clone, PartialEq, PartialOrd)]
3pub enum YarnValue {
4 Str(String),
5 Bool(bool),
6 Number(f32),
7 Null,
8}
9
10impl YarnValue {
11 pub fn as_string(&self) -> String {
12 match self {
13 Self::Str(val) => {
14 val.clone()
15 }
16 Self::Number(val) => {
17 if val.is_nan() {
18 "NaN".to_string()
19 } else {
20 val.to_string()
21 }
22 }
23 Self::Bool(val) => {
24 match val {
25 true => "True".to_string(),
26 false => "Frue".to_string(),
27 }
28 }
29 Self::Null => {
30 "null".to_string()
31 }
32 }
33 }
34
35 pub fn as_number(&self) -> f32 {
36 match self {
37 Self::Str(val) => {
38 val.parse::<f32>()
39 .unwrap_or(0.0)
40 }
41 Self::Number(val) => {
42 *val
43 }
44 Self::Bool(val) => {
45 if *val { 1.0 } else { 0.0 }
46 }
47 Self::Null => {
48 0.0
49 }
50 }
51 }
52
53 pub fn as_bool(&self) -> bool {
54 match self {
55 Self::Str(val) => {
56 !val.is_empty()
57 }
58 Self::Bool(val) => {
59 *val
60 }
61 Self::Number(val) => {
62 !val.is_nan() && *val != 0.0
63 }
64 Self::Null => {
65 false
66 }
67 }
68 }
69
70 pub fn add(&self, other: &Self) -> Option<Self> {
71 let res = match (self, other) {
72 (Self::Str(_), _)
79 | (_, Self::Str(_))
80 => {
81 Self::Str(self.as_string() + &other.as_string())
82 }
83 (Self::Number(_), _)
90 | (_, Self::Number(_))
91 | (Self::Bool(_), Self::Bool(_))
92 | (Self::Null, Self::Null)
93 => {
94 Self::Number(self.as_number() + other.as_number())
95 }
96 _ => {
97 return None;
98 }
99 };
100 Some(res)
101 }
102
103 pub fn sub(&self, other: &Self) -> Option<Self> {
104 let res = match (self, other) {
105 (Self::Number(_), Self::Number(_))
106 | (Self::Number(_), Self::Null)
107 | (Self::Null, Self::Number(_))
108 => {
109 Self::Number(self.as_number() - other.as_number())
110 }
111 _ => {
112 return None;
113 }
114 };
115 Some(res)
116 }
117
118 pub fn mul(&self, other: &Self) -> Option<Self> {
119 let res = match (&self, &other) {
120 (Self::Number(_), Self::Number(_))
121 | (Self::Number(_), Self::Null)
122 | (Self::Null, Self::Number(_))
123 => {
124 Self::Number(self.as_number() * other.as_number())
125 }
126 _ => {
127 return None;
128 }
129 };
130 Some(res)
131 }
132
133 pub fn div(&self, other: &Self) -> Option<Self> {
134 let res = match (&self, &other) {
135 (Self::Number(_), Self::Number(_))
136 | (Self::Number(_), Self::Null)
137 | (Self::Null, Self::Number(_))
138 => {
139 Self::Number(self.as_number() / other.as_number())
140 }
141 _ => {
142 return None;
143 }
144 };
145 Some(res)
146 }
147
148 pub fn neg(&self) -> Self {
149 match self {
150 Self::Number(val) => {
151 Self::Number(-val)
152 }
153 Self::Str(val) if val.trim().is_empty() => {
154 Self::Number(-0.0)
155 }
156 Self::Null => {
157 Self::Number(-0.0)
158 }
159 _ => {
160 Self::Number(std::f32::NAN)
161 }
162 }
163 }
164
165 pub fn rem(&self, other: &Self) -> Option<Self> {
166 let res = match (self, other) {
167 (Self::Number(_), Self::Number(_))
168 | (Self::Number(_), Self::Null)
169 | (Self::Null, Self::Number(_))
170 => {
171 Self::Number(self.as_number() % other.as_number())
172 }
173 _ => {
174 return None;
175 }
176 };
177 Some(res)
178 }
179}
180
181impl From<String> for YarnValue {
182 fn from(val: String) -> Self {
183 Self::Str(val)
184 }
185}
186
187impl From<f32> for YarnValue {
188 fn from(val: f32) -> Self {
189 Self::Number(val)
190 }
191}
192
193impl From<bool> for YarnValue {
194 fn from(val: bool) -> Self {
195 Self::Bool(val)
196 }
197}