mini_builder_rs/
value.rs

1//! The data types and their interactions that are used in the language
2
3use std::borrow::Borrow;
4
5use approx::{relative_eq, relative_ne};
6
7// TODO: epsilon compare, should text be `Cow` to save on copies?
8#[derive(Debug, Clone, PartialEq)]
9pub enum Value {
10	Number(f32),
11	Bool(bool),
12	Text(String),
13	List(Vec<Value>),
14	None,
15}
16
17impl Value {
18	// constructors
19	pub fn text(text: impl ToString) -> Value {
20		Value::Text(text.to_string())
21	}
22
23	// general
24	pub fn is_none(&self) -> bool {
25		match self {
26			Self::None => true,
27			_ => false,
28		}
29	}
30
31	pub fn bool_or_false(&self) -> bool {
32		match self {
33			Self::Bool(b) => *b,
34			_ => false,
35		}
36	}
37
38	// arithmetics
39	pub fn add(&self, other: &Self) -> Self {
40		if let Self::List(l1) = self {
41			let mut l1 = l1.clone();
42			if let Self::List(l2) = other {
43				let l2 = l2.clone();
44				l1.extend(l2);
45			} else {
46				l1.push(other.clone());
47			}
48			Self::List(l1)
49		} else if let Self::List(l2) = other {
50			let mut l2 = l2.clone();
51			l2.insert(0, self.clone());
52			Self::List(l2)
53		} else {
54			match self {
55				Self::Number(a) => match other {
56					Self::Number(b) => Self::Number(*a + *b),
57					Self::Bool(b) => Self::Number(*a + if *b { 1.0 } else { 0.0 }),
58					Self::Text(b) => Self::Text(format!("{a}{b}")),
59					Self::None => self.clone(),
60					_ => Self::None,
61				},
62				Self::Bool(a) => match other {
63					Self::Number(b) => Self::Number(if *a { 1.0 } else { 0.0 } + *b),
64					Self::Text(b) => {
65						Self::Text(format!("{}{b}", if *a { "true" } else { "false" }))
66					}
67					_ => Self::None,
68				},
69				Self::Text(a) => match other {
70					Self::Number(b) => Self::Text(format!("{a}{b}")),
71					Self::Bool(b) => {
72						Self::Text(format!("{a}{}", if *b { "true" } else { "false" }))
73					}
74					Self::Text(b) => Self::Text(format!("{a}{b}")),
75					Self::None => self.clone(),
76					_ => Self::None,
77				},
78				Self::None => other.clone(),
79				_ => Self::None,
80			}
81		}
82	}
83
84	pub fn sub(&self, other: &Self) -> Self {
85		match self {
86			Self::Number(a) => match other {
87				Self::Number(b) => Self::Number(*a - *b),
88				_ => Self::None,
89			},
90			_ => Self::None,
91		}
92	}
93
94	pub fn mul(&self, other: &Self) -> Self {
95		match self {
96			Self::Number(a) => match other {
97				Self::Number(b) => Self::Number(*a * *b),
98				_ => Self::None,
99			},
100			_ => Self::None,
101		}
102	}
103
104	pub fn div(&self, other: &Self) -> Self {
105		match self {
106			Self::Number(a) => match other {
107				Self::Number(b) => Self::Number(*a / *b),
108				_ => Self::None,
109			},
110			_ => Self::None,
111		}
112	}
113
114	pub fn neg(&self) -> Self {
115		match self {
116			Self::Number(a) => Self::Number(-*a),
117			_ => Self::None,
118		}
119	}
120
121	// logic
122	pub fn not(&self) -> Self {
123		match self {
124			Self::Bool(a) => Self::Bool(!*a),
125			_ => Self::None,
126		}
127	}
128
129	fn logic_helper(&self, other: &Self, op: impl Fn(bool, bool) -> bool) -> Value {
130		match self {
131			Self::Bool(a) => match other {
132				Self::Bool(b) => Self::Bool(op(*a, *b)),
133				_ => Self::None,
134			},
135			_ => Self::None,
136		}
137	}
138
139	pub fn or(&self, other: &Self) -> Self {
140		Self::logic_helper(&self, other, |a, b| a || b)
141	}
142
143	pub fn and(&self, other: &Self) -> Self {
144		Self::logic_helper(&self, other, |a, b| a && b)
145	}
146
147	// comparisons
148	fn compare_numbers(&self, other: &Self, op: impl Fn(f32, f32) -> bool) -> Value {
149		match self {
150			Self::Number(a) => match other {
151				Self::Number(b) => Self::Bool(op(*a, *b)),
152				_ => Self::None,
153			},
154			_ => Self::None,
155		}
156	}
157
158	pub fn less_than(&self, other: &Self) -> Self {
159		self.compare_numbers(other, |a, b| a < b)
160	}
161
162	pub fn less_equals(&self, other: &Self) -> Self {
163		self.compare_numbers(other, |a, b| a <= b)
164	}
165
166	pub fn greater_than(&self, other: &Self) -> Self {
167		self.compare_numbers(other, |a, b| a > b)
168	}
169
170	pub fn greater_equals(&self, other: &Self) -> Self {
171		self.compare_numbers(other, |a, b| a >= b)
172	}
173
174	pub fn equals(&self, other: &Self) -> Self {
175		if let (Self::Number(a), Self::Number(b)) = (self, other) {
176			return Self::Bool(relative_eq!(*a, *b));
177		}
178
179		if let (Self::Bool(a), Self::Bool(b)) = (self, other) {
180			return Self::Bool(a == b);
181		}
182
183		if let (Self::Text(a), Self::Text(b)) = (self, other) {
184			return Self::Bool(a == b);
185		}
186
187		if self.is_none() && other.is_none() {
188			return Self::Bool(true);
189		}
190
191		if self.is_none() || other.is_none() {
192			return Self::Bool(false);
193		}
194
195		Self::None
196	}
197
198	pub fn not_equals(&self, other: &Self) -> Self {
199		if let (Self::Number(a), Self::Number(b)) = (self, other) {
200			return Self::Bool(!relative_ne!(*a, *b));
201		}
202
203		if let (Self::Bool(a), Self::Bool(b)) = (self, other) {
204			return Self::Bool(a != b);
205		}
206
207		if let (Self::Text(a), Self::Text(b)) = (self, other) {
208			return Self::Bool(a != b);
209		}
210
211		if self.is_none() && other.is_none() {
212			return Self::Bool(false);
213		}
214
215		if self.is_none() || other.is_none() {
216			return Self::Bool(true);
217		}
218
219		Self::None
220	}
221}
222
223impl<B: Borrow<Value>> std::ops::Add<B> for &Value {
224	type Output = Value;
225
226	fn add(self, rhs: B) -> Self::Output {
227		Value::add(&self, rhs.borrow())
228	}
229}
230
231impl ToString for Value {
232	fn to_string(&self) -> String {
233		match self {
234			Self::Number(a) => a.to_string(),
235			Self::Bool(a) => a.to_string(),
236			Self::Text(a) => a.to_string(),
237			Self::List(l) => format!(
238				"[{}]",
239				l.iter()
240					.map(|v| v.to_string())
241					.collect::<Vec<_>>()
242					.join(", ")
243			),
244			Self::None => String::new(),
245		}
246	}
247}