1use crate::value::Value;
2use std::ops::{Add, Div, Mul, Neg, Sub};
3use vek::Vec3;
4
5#[derive(Clone, Debug, PartialEq)]
6pub struct VMValue {
7 pub x: f32,
8 pub y: f32,
9 pub z: f32,
10 pub string: Option<String>,
11}
12
13impl VMValue {
14 pub fn new(x: f32, y: f32, z: f32) -> Self {
15 Self {
16 x,
17 y,
18 z,
19 string: None,
20 }
21 }
22
23 pub fn new_with_string<S: Into<String>>(x: f32, y: f32, z: f32, s: S) -> Self {
25 Self {
26 x,
27 y,
28 z,
29 string: Some(s.into()),
30 }
31 }
32
33 pub fn broadcast(v: f32) -> Self {
34 Self {
35 x: v,
36 y: v,
37 z: v,
38 string: None,
39 }
40 }
41
42 pub fn zero() -> Self {
43 Self::broadcast(0.0)
44 }
45
46 pub fn from_bool(v: bool) -> Self {
47 Self::broadcast(if v { 1.0 } else { 0.0 })
48 }
49
50 pub fn from_i32(v: i32) -> Self {
51 Self::broadcast(v as f32)
52 }
53
54 pub fn from_f32(v: f32) -> Self {
55 Self::broadcast(v)
56 }
57
58 pub fn from_u32(v: u32) -> Self {
59 Self::broadcast(v as f32)
60 }
61
62 pub fn from<T: Into<VMValue>>(v: T) -> Self {
64 v.into()
65 }
66
67 pub fn from_vec3(v: Vec3<f32>) -> Self {
68 Self {
69 x: v.x,
70 y: v.y,
71 z: v.z,
72 string: None,
73 }
74 }
75
76 pub fn to_vec3(&self) -> Vec3<f32> {
77 Vec3::new(self.x, self.y, self.z)
78 }
79
80 pub fn from_string<S: Into<String>>(s: S) -> Self {
81 Self {
82 x: 0.0,
83 y: 0.0,
84 z: 0.0,
85 string: Some(s.into()),
86 }
87 }
88
89 pub fn as_string(&self) -> Option<&str> {
90 self.string.as_deref()
91 }
92
93 pub fn from_value(value: &Value) -> Self {
94 match value {
95 Value::NoValue => VMValue::zero(),
96 Value::Bool(b) => VMValue::broadcast(if *b { 1.0 } else { 0.0 }),
97 Value::Int(i) => VMValue::broadcast(*i as f32),
98 Value::UInt(i) => VMValue::broadcast(*i as f32),
99 Value::Int64(i) => VMValue::broadcast(*i as f32),
100 Value::Float(f) => VMValue::broadcast(*f),
101 Value::Vec2(v) => VMValue::new(v[0], v[1], 0.0),
102 Value::Vec3(v) => VMValue::new(v[0], v[1], v[2]),
103 Value::Vec4(v) => VMValue::new(v[0], v[1], v[2]),
104 Value::Str(s) => VMValue::from_string(s.clone()),
105 _ => VMValue::zero(),
106 }
107 }
108
109 pub fn to_value(&self) -> Value {
111 if let Some(s) = self.as_string() {
112 Value::Str(s.to_string())
113 } else if self.x == self.y && self.x == self.z {
114 Value::Float(self.x)
115 } else {
116 Value::Vec3([self.x, self.y, self.z])
117 }
118 }
119
120 pub fn to_value_with_hint(&self, hint: Option<&Value>) -> Value {
122 if let Some(s) = self.as_string() {
124 let s_trim = s.trim();
125 if let Some(tagged) = Self::from_type_tagged_str(s_trim) {
127 return tagged;
128 }
129 match s_trim.to_ascii_lowercase().as_str() {
130 "bool" => return Value::Bool(self.to_bool()),
131 "int" => return Value::Int(self.x as i32),
132 "uint" => return Value::UInt(self.x.max(0.0) as u32),
133 "i64" | "int64" => return Value::Int64(self.x as i64),
134 "float" | "f32" => return Value::Float(self.x),
135 "vec2" => return Value::Vec2([self.x, self.y]),
136 "vec3" => return Value::Vec3([self.x, self.y, self.z]),
137 "str" | "string" => {
138 return Value::Str(Self::to_string_lossy_components(self.x, self.y, self.z));
139 }
140 _ => {}
141 }
142 }
143
144 match hint {
145 Some(Value::Bool(_)) => Value::Bool(self.to_bool()),
146 Some(Value::Int(_)) => Value::Int(self.x as i32),
147 Some(Value::UInt(_)) => Value::UInt(self.x.max(0.0) as u32),
148 Some(Value::Int64(_)) => Value::Int64(self.x as i64),
149 Some(Value::Float(_)) => Value::Float(self.x),
150 Some(Value::Vec2(_)) => Value::Vec2([self.x, self.y]),
151 Some(Value::Vec3(_)) => Value::Vec3([self.x, self.y, self.z]),
152 Some(Value::Vec4(_)) => Value::Vec4([self.x, self.y, self.z, 0.0]),
153 Some(Value::Str(_)) => Value::Str(
154 self.as_string()
155 .map(|s| s.to_string())
156 .unwrap_or_else(|| format!("{}", self.x)),
157 ),
158 Some(Value::StrArray(_)) => Value::StrArray(vec![
159 self.as_string()
160 .map(|s| s.to_string())
161 .unwrap_or_else(|| format!("{}", self.x)),
162 ]),
163 _ => {
164 if let Some(s) = self.as_string() {
166 if let Some(b) = Self::parse_bool_str(s) {
167 return Value::Bool(b);
168 }
169 if let Ok(i) = s.parse::<i32>() {
170 return Value::Int(i);
171 }
172 if let Ok(f) = s.parse::<f32>() {
173 return Value::Float(f);
174 }
175 return Value::Str(s.to_string());
176 }
177 if self.x == self.y && self.x == self.z {
178 Value::Float(self.x)
179 } else {
180 Value::Vec3([self.x, self.y, self.z])
181 }
182 }
183 }
184 }
185
186 pub fn to_bool(&self) -> bool {
187 if let Some(s) = self.as_string() {
188 if let Some(b) = Self::parse_bool_str(s) {
189 return b;
190 }
191 }
192 self.x != 0.0 || self.y != 0.0 || self.z != 0.0
194 }
195
196 pub fn is_truthy(&self) -> bool {
197 if let Some(s) = &self.string {
198 !s.is_empty()
199 } else {
200 self.x != 0.0 || self.y != 0.0 || self.z != 0.0
201 }
202 }
203
204 fn parse_bool_str(s: &str) -> Option<bool> {
205 match s.trim().to_ascii_lowercase().as_str() {
206 "true" | "1" | "yes" | "on" => Some(true),
207 "false" | "0" | "no" | "off" => Some(false),
208 _ => None,
209 }
210 }
211
212 fn from_type_tagged_str(s: &str) -> Option<Value> {
213 let (tag, rest) = s.split_once(':')?;
214 let tag = tag.trim().to_ascii_lowercase();
215 let rest = rest.trim();
216
217 match tag.as_str() {
218 "bool" => Self::parse_bool_str(rest).map(Value::Bool),
219 "int" => rest.parse::<i32>().ok().map(Value::Int),
220 "uint" => rest.parse::<u32>().ok().map(Value::UInt),
221 "i64" | "int64" => rest.parse::<i64>().ok().map(Value::Int64),
222 "float" | "f32" => rest.parse::<f32>().ok().map(Value::Float),
223 "vec2" => parse_vec(rest, 2).map(|v| Value::Vec2([v[0], v[1]])),
224 "vec3" => parse_vec(rest, 3).map(|v| Value::Vec3([v[0], v[1], v[2]])),
225 "str" | "string" => Some(Value::Str(rest.to_string())),
226 _ => None,
227 }
228 }
229
230 pub fn magnitude(&self) -> f32 {
231 self.to_vec3().magnitude()
232 }
233
234 pub fn map<F: Fn(f32) -> f32>(&self, f: F) -> Self {
235 VMValue::new(f(self.x), f(self.y), f(self.z))
236 }
237
238 pub fn map2<F: Fn(f32, f32) -> f32>(&self, other: VMValue, f: F) -> Self {
239 VMValue::new(f(self.x, other.x), f(self.y, other.y), f(self.z, other.z))
240 }
241
242 pub fn dot(&self, other: VMValue) -> f32 {
243 self.to_vec3().dot(other.to_vec3())
244 }
245
246 pub fn cross(&self, other: VMValue) -> Self {
247 VMValue::from_vec3(self.to_vec3().cross(other.to_vec3()))
248 }
249
250 fn format_scalar(v: f32) -> String {
251 if v.fract() == 0.0 {
252 format!("{:.0}", v)
253 } else {
254 v.to_string()
255 }
256 }
257
258 fn to_string_lossy_components(x: f32, y: f32, z: f32) -> String {
259 if x == y && y == z {
260 Self::format_scalar(x)
261 } else {
262 format!("{},{},{}", x, y, z)
263 }
264 }
265
266 fn _to_string_lossy(&self) -> String {
267 Self::to_string_lossy_components(self.x, self.y, self.z)
268 }
269}
270
271impl std::fmt::Display for VMValue {
272 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
273 if let Some(s) = &self.string {
274 let tag = s.trim();
275 let tag_l = tag.to_ascii_lowercase();
276
277 if let Some(val) = Self::from_type_tagged_str(tag) {
278 return write!(f, "{}", format_value_brief(&val));
279 }
280
281 return match tag_l.as_str() {
282 "bool" => write!(f, "{}", self.to_bool()),
283 "int" => write!(f, "{}", self.x as i32),
284 "uint" => write!(f, "{}", self.x.max(0.0) as u32),
285 "i64" | "int64" => write!(f, "{}", self.x as i64),
286 "float" | "f32" => write!(f, "{}", self.x),
287 "vec2" => write!(f, "[{}, {}]", self.x, self.y),
288 "vec3" => write!(f, "[{}, {}, {}]", self.x, self.y, self.z),
289 "vec4" => write!(f, "[{}, {}, {}, 0]", self.x, self.y, self.z),
290 "str" | "string" => {
291 write!(
292 f,
293 "{}",
294 Self::to_string_lossy_components(self.x, self.y, self.z)
295 )
296 }
297 _ => write!(f, "{}", s),
298 };
299 }
300
301 if self.x == self.y && self.x == self.z {
302 write!(f, "{}", self.x)
303 } else {
304 write!(f, "[{}, {}, {}]", self.x, self.y, self.z)
305 }
306 }
307}
308
309fn format_value_brief(v: &Value) -> String {
310 match v {
311 Value::Bool(b) => b.to_string(),
312 Value::Int(i) => i.to_string(),
313 Value::UInt(u) => u.to_string(),
314 Value::Int64(i) => i.to_string(),
315 Value::Float(f) => f.to_string(),
316 Value::Vec2(v) => format!("[{}, {}]", v[0], v[1]),
317 Value::Vec3(v) => format!("[{}, {}, {}]", v[0], v[1], v[2]),
318 Value::Vec4(v) => format!("[{}, {}, {}, {}]", v[0], v[1], v[2], v[3]),
319 Value::Str(s) => s.clone(),
320 _ => format!("{:?}", v),
321 }
322}
323
324impl Add for VMValue {
325 type Output = VMValue;
326
327 fn add(self, rhs: VMValue) -> Self::Output {
328 let (ax, ay, az) = (self.x, self.y, self.z);
329 let (bx, by, bz) = (rhs.x, rhs.y, rhs.z);
330 match (self.string, rhs.string) {
331 (Some(a), Some(b)) => VMValue::from_string(format!("{a}{b}")),
332 (Some(a), None) => {
333 let b_str = VMValue::to_string_lossy_components(bx, by, bz);
334 VMValue::from_string(format!("{a}{b_str}"))
335 }
336 (None, Some(b)) => {
337 let a_str = VMValue::to_string_lossy_components(ax, ay, az);
338 VMValue::from_string(format!("{a_str}{b}"))
339 }
340 _ => VMValue::new(ax + bx, ay + by, az + bz),
341 }
342 }
343}
344
345impl Sub for VMValue {
346 type Output = VMValue;
347
348 fn sub(self, rhs: VMValue) -> Self::Output {
349 VMValue::new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z)
350 }
351}
352
353impl Mul for VMValue {
354 type Output = VMValue;
355
356 fn mul(self, rhs: VMValue) -> Self::Output {
357 VMValue::new(self.x * rhs.x, self.y * rhs.y, self.z * rhs.z)
358 }
359}
360
361impl Div for VMValue {
362 type Output = VMValue;
363
364 fn div(self, rhs: VMValue) -> Self::Output {
365 VMValue::new(self.x / rhs.x, self.y / rhs.y, self.z / rhs.z)
366 }
367}
368
369impl Neg for VMValue {
370 type Output = VMValue;
371
372 fn neg(self) -> Self::Output {
373 VMValue::new(-self.x, -self.y, -self.z)
374 }
375}
376
377impl From<bool> for VMValue {
378 fn from(v: bool) -> Self {
379 VMValue::from_bool(v)
380 }
381}
382
383impl From<i32> for VMValue {
384 fn from(v: i32) -> Self {
385 VMValue::from_i32(v)
386 }
387}
388
389impl From<u32> for VMValue {
390 fn from(v: u32) -> Self {
391 VMValue::from_u32(v)
392 }
393}
394
395impl From<f32> for VMValue {
396 fn from(v: f32) -> Self {
397 VMValue::from_f32(v)
398 }
399}
400
401impl From<String> for VMValue {
402 fn from(s: String) -> Self {
403 VMValue::from_string(s)
404 }
405}
406
407impl From<&str> for VMValue {
408 fn from(s: &str) -> Self {
409 VMValue::from_string(s)
410 }
411}
412
413impl From<Value> for VMValue {
414 fn from(v: Value) -> Self {
415 VMValue::from_value(&v)
416 }
417}
418
419impl From<Vec3<f32>> for VMValue {
420 fn from(v: Vec3<f32>) -> Self {
421 VMValue::from_vec3(v)
422 }
423}
424
425fn parse_vec(s: &str, expected: usize) -> Option<Vec<f32>> {
426 let vals: Vec<f32> = s
427 .split(',')
428 .filter_map(|p| p.trim().parse::<f32>().ok())
429 .collect();
430 if vals.len() == expected {
431 Some(vals)
432 } else {
433 None
434 }
435}