mica_language/value/
mod.rs

1//! Dynamically typed values.
2//!
3//! This module abstracts platform specifics such as NaN boxing away into a common interface.
4
5mod closures;
6mod dicts;
7mod impls;
8mod lists;
9mod structs;
10mod traits;
11
12use std::any::Any;
13use std::borrow::Cow;
14use std::cmp::Ordering;
15use std::fmt;
16use std::fmt::Write;
17use std::ops::Deref;
18
19use crate::bytecode::DispatchTable;
20use crate::common::ErrorKind;
21use crate::gc::GcRaw;
22
23use impls::ValueImpl;
24
25pub use closures::*;
26pub use dicts::*;
27pub use lists::*;
28pub use structs::*;
29pub use traits::*;
30
31/// The kind of a value.
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
33pub enum ValueKind {
34   Nil,
35   Boolean,
36   Number,
37   String,
38   Function,
39   Struct,
40   Trait,
41   List,
42   Dict,
43   UserData,
44}
45
46/// Common interface each `ValueImpl` must implement.
47trait ValueCommon: Clone + PartialEq {
48   fn new_nil() -> Self;
49   fn new_boolean(b: bool) -> Self;
50   fn new_number(n: f64) -> Self;
51   fn new_string(s: GcRaw<String>) -> Self;
52   fn new_function(f: GcRaw<Closure>) -> Self;
53   fn new_struct(s: GcRaw<Struct>) -> Self;
54   fn new_trait(s: GcRaw<Trait>) -> Self;
55   fn new_list(s: GcRaw<List>) -> Self;
56   fn new_dict(d: GcRaw<Dict>) -> Self;
57   fn new_user_data(u: GcRaw<Box<dyn UserData>>) -> Self;
58
59   fn kind(&self) -> ValueKind;
60
61   unsafe fn get_boolean_unchecked(&self) -> bool;
62   // This returns a reference such that mica-hl can use `f64` as a `self` parameter in methods.
63   unsafe fn get_number_unchecked(&self) -> &f64;
64   unsafe fn get_raw_string_unchecked(&self) -> GcRaw<String>;
65   unsafe fn get_raw_function_unchecked(&self) -> GcRaw<Closure>;
66   unsafe fn get_raw_struct_unchecked(&self) -> GcRaw<Struct>;
67   unsafe fn get_raw_trait_unchecked(&self) -> GcRaw<Trait>;
68   unsafe fn get_raw_list_unchecked(&self) -> GcRaw<List>;
69   unsafe fn get_raw_dict_unchecked(&self) -> GcRaw<Dict>;
70   unsafe fn get_raw_user_data_unchecked(&self) -> GcRaw<Box<dyn UserData>>;
71}
72
73fn _check_implementations() {
74   fn check_value<T: ValueCommon>() {}
75   check_value::<ValueImpl>();
76}
77
78/// A dynamically-typed, raw value. Does not provide **any** safety guarantees.
79#[derive(Clone, Copy, PartialEq)]
80#[repr(transparent)]
81pub struct RawValue(ValueImpl);
82
83impl RawValue {
84   /// Returns the kind of value stored.
85   pub fn kind(&self) -> ValueKind {
86      self.0.kind()
87   }
88
89   fn type_name(&self) -> Cow<'static, str> {
90      match self.0.kind() {
91         ValueKind::Nil => "Nil".into(),
92         ValueKind::Boolean => "Boolean".into(),
93         ValueKind::Number => "Number".into(),
94         ValueKind::String => "String".into(),
95         ValueKind::Function => "Function".into(),
96         ValueKind::List => "List".into(),
97         ValueKind::Dict => "Dict".into(),
98         ValueKind::Struct => unsafe { self.0.get_raw_struct_unchecked().get().dtable() }
99            .type_name
100            .deref()
101            .to_owned()
102            .into(),
103         ValueKind::Trait => unsafe { self.0.get_raw_trait_unchecked().get().dtable() }
104            .type_name
105            .deref()
106            .to_owned()
107            .into(),
108         ValueKind::UserData => unsafe { self.0.get_raw_user_data_unchecked().get().dtable() }
109            .type_name
110            .deref()
111            .to_owned()
112            .into(),
113      }
114   }
115
116   fn type_error(&self, expected: &'static str) -> ErrorKind {
117      ErrorKind::TypeError {
118         expected: Cow::from(expected),
119         got: self.type_name(),
120      }
121   }
122
123   /// Returns a boolean value without performing any checks.
124   ///
125   /// # Safety
126   /// Calling this on a value that isn't known to be a boolean is undefined behavior.
127   pub unsafe fn get_boolean_unchecked(&self) -> bool {
128      self.0.get_boolean_unchecked()
129   }
130
131   /// Returns a number value without performing any checks.
132   ///
133   /// # Safety
134   /// Calling this on a value that isn't known to be a number is undefined behavior.
135   pub unsafe fn get_number_unchecked(&self) -> &f64 {
136      self.0.get_number_unchecked()
137   }
138
139   /// Returns a string value without performing any checks.
140   ///
141   /// # Safety
142   /// Calling this on a value that isn't known to be a string is undefined behavior.
143   pub unsafe fn get_raw_string_unchecked(&self) -> GcRaw<String> {
144      self.0.get_raw_string_unchecked()
145   }
146
147   /// Returns a function value without performing any checks.
148   ///
149   /// # Safety
150   /// Calling this on a value that isn't known to be a function is undefined behavior.
151   pub unsafe fn get_raw_function_unchecked(&self) -> GcRaw<Closure> {
152      self.0.get_raw_function_unchecked()
153   }
154
155   /// Returns a struct value without performing any checks.
156   ///
157   /// # Safety
158   /// Calling this on a value that isn't known to be a struct is undefined behavior.
159   pub unsafe fn get_raw_struct_unchecked(&self) -> GcRaw<Struct> {
160      self.0.get_raw_struct_unchecked()
161   }
162
163   /// Returns a trait value without performing any checks.
164   ///
165   /// # Safety
166   /// Calling this on a value that isn't known to be a trait is undefined behavior.
167   pub unsafe fn get_raw_trait_unchecked(&self) -> GcRaw<Trait> {
168      self.0.get_raw_trait_unchecked()
169   }
170
171   /// Returns a list value without performing any checks.
172   ///
173   /// # Safety
174   /// Calling this on a value that isn't known to be a list is undefined behavior.
175   pub unsafe fn get_raw_list_unchecked(&self) -> GcRaw<List> {
176      self.0.get_raw_list_unchecked()
177   }
178
179   /// Returns a dict value without performing any checks.
180   ///
181   /// # Safety
182   /// Calling this on a value that isn't known to be a dict is undefined behavior.
183   pub unsafe fn get_raw_dict_unchecked(&self) -> GcRaw<Dict> {
184      self.0.get_raw_dict_unchecked()
185   }
186
187   /// Returns a user data value without performing any checks.
188   ///
189   /// # Safety
190   /// Calling this on a value that isn't known to be a user data is undefined behavior.
191   pub unsafe fn get_raw_user_data_unchecked(&self) -> GcRaw<Box<dyn UserData>> {
192      self.0.get_raw_user_data_unchecked()
193   }
194
195   /// Ensures the value is a `Nil`, returning a type mismatch error if that's not the case.
196   pub fn ensure_nil(&self) -> Result<(), ErrorKind> {
197      if self.0.kind() == ValueKind::Nil {
198         Ok(())
199      } else {
200         Err(self.type_error("Nil"))
201      }
202   }
203
204   /// Ensures the value is a `Boolean`, returning a type mismatch error if that's not the case.
205   pub fn ensure_boolean(&self) -> Result<bool, ErrorKind> {
206      if self.0.kind() == ValueKind::Boolean {
207         Ok(unsafe { self.0.get_boolean_unchecked() })
208      } else {
209         Err(self.type_error("Boolean"))
210      }
211   }
212
213   /// Ensures the value is a `Number`, returning a type mismatch error if that's not the case.
214   pub fn ensure_number(&self) -> Result<f64, ErrorKind> {
215      if self.0.kind() == ValueKind::Number {
216         Ok(unsafe { *self.0.get_number_unchecked() })
217      } else {
218         Err(self.type_error("Number"))
219      }
220   }
221
222   /// Ensures the value is a `String`, returning a type mismatch error if that's not the case.
223   pub fn ensure_raw_string(&self) -> Result<GcRaw<String>, ErrorKind> {
224      if self.0.kind() == ValueKind::String {
225         Ok(unsafe { self.0.get_raw_string_unchecked() })
226      } else {
227         Err(self.type_error("String"))
228      }
229   }
230
231   /// Ensures the value is a `Function`, returning a type mismatch error if that's not the case.
232   pub fn ensure_raw_function(&self) -> Result<GcRaw<Closure>, ErrorKind> {
233      if self.0.kind() == ValueKind::Function {
234         Ok(unsafe { self.0.get_raw_function_unchecked() })
235      } else {
236         Err(self.type_error("Function"))
237      }
238   }
239
240   /// Ensures the value is a `Struct`, returning a type mismatch error if that's not the case.
241   pub fn ensure_raw_struct(&self) -> Result<GcRaw<Struct>, ErrorKind> {
242      if self.0.kind() == ValueKind::Struct {
243         Ok(unsafe { self.0.get_raw_struct_unchecked() })
244      } else {
245         Err(self.type_error("any struct"))
246      }
247   }
248
249   /// Ensures the value is a `Trait`, returning a type mismatch error if that's not the case.
250   pub fn ensure_raw_trait(&self) -> Result<GcRaw<Trait>, ErrorKind> {
251      if self.0.kind() == ValueKind::Trait {
252         Ok(unsafe { self.0.get_raw_trait_unchecked() })
253      } else {
254         Err(self.type_error("any trait"))
255      }
256   }
257
258   /// Ensures the value is a `UserData` of the given type `T`, returning a type mismatch error
259   /// that's not the case.
260   pub fn get_raw_user_data<T>(&self) -> Option<GcRaw<Box<dyn UserData>>>
261   where
262      T: UserData,
263   {
264      if self.0.kind() == ValueKind::UserData {
265         Some(unsafe { self.0.get_raw_user_data_unchecked() })
266      } else {
267         None
268      }
269   }
270
271   /// Returns whether the value is truthy. All values except `Nil` and `False` are truthy.
272   pub fn is_truthy(&self) -> bool {
273      !self.is_falsy()
274   }
275
276   /// Returns whether the values is falsy. The only falsy values are `Nil` and `False`.
277   pub fn is_falsy(&self) -> bool {
278      self.0.kind() == ValueKind::Nil
279         || (self.0.kind() == ValueKind::Boolean && unsafe { !self.0.get_boolean_unchecked() })
280   }
281
282   /// Attempts to partially compare this value with another one.
283   ///
284   /// Returns an error if the types of the two values are not the same.
285   pub fn try_partial_cmp(&self, other: &Self) -> Result<Option<Ordering>, ErrorKind> {
286      if self.0.kind() != other.0.kind() {
287         Err(ErrorKind::TypeError {
288            expected: self.type_name(),
289            got: other.type_name(),
290         })
291      } else {
292         match self.0.kind() {
293            ValueKind::Nil => Ok(Some(Ordering::Equal)),
294            ValueKind::Boolean => {
295               let a = unsafe { self.0.get_boolean_unchecked() };
296               let b = unsafe { other.0.get_boolean_unchecked() };
297               Ok(Some(a.cmp(&b)))
298            }
299            ValueKind::Number => {
300               let a = unsafe { self.0.get_number_unchecked() };
301               let b = unsafe { other.0.get_number_unchecked() };
302               Ok(a.partial_cmp(b))
303            }
304            ValueKind::String => unsafe {
305               let a = self.0.get_raw_string_unchecked();
306               let b = other.0.get_raw_string_unchecked();
307               Ok(Some(a.get().cmp(b.get())))
308            },
309            ValueKind::Function => Ok(None),
310            ValueKind::Struct => Ok(None),
311            ValueKind::Trait => Ok(None),
312            ValueKind::List => unsafe {
313               let a = self.0.get_raw_list_unchecked();
314               let b = other.0.get_raw_list_unchecked();
315               a.get().try_partial_cmp(b.get())
316            },
317            ValueKind::Dict => todo!(),
318            ValueKind::UserData => Ok(None),
319         }
320      }
321   }
322}
323
324impl Default for RawValue {
325   fn default() -> Self {
326      Self(ValueImpl::new_nil())
327   }
328}
329
330impl From<()> for RawValue {
331   fn from(_: ()) -> Self {
332      Self(ValueImpl::new_nil())
333   }
334}
335
336impl From<bool> for RawValue {
337   fn from(b: bool) -> Self {
338      Self(ValueImpl::new_boolean(b))
339   }
340}
341
342impl From<f64> for RawValue {
343   fn from(x: f64) -> Self {
344      Self(ValueImpl::new_number(x))
345   }
346}
347
348impl From<GcRaw<String>> for RawValue {
349   fn from(s: GcRaw<String>) -> Self {
350      Self(ValueImpl::new_string(s))
351   }
352}
353
354impl From<GcRaw<Closure>> for RawValue {
355   fn from(f: GcRaw<Closure>) -> Self {
356      Self(ValueImpl::new_function(f))
357   }
358}
359
360impl From<GcRaw<Struct>> for RawValue {
361   fn from(s: GcRaw<Struct>) -> Self {
362      Self(ValueImpl::new_struct(s))
363   }
364}
365
366impl From<GcRaw<Trait>> for RawValue {
367   fn from(t: GcRaw<Trait>) -> Self {
368      Self(ValueImpl::new_trait(t))
369   }
370}
371
372impl From<GcRaw<List>> for RawValue {
373   fn from(s: GcRaw<List>) -> Self {
374      Self(ValueImpl::new_list(s))
375   }
376}
377
378impl From<GcRaw<Dict>> for RawValue {
379   fn from(s: GcRaw<Dict>) -> Self {
380      Self(ValueImpl::new_dict(s))
381   }
382}
383
384impl From<GcRaw<Box<dyn UserData>>> for RawValue {
385   fn from(u: GcRaw<Box<dyn UserData>>) -> Self {
386      Self(ValueImpl::new_user_data(u))
387   }
388}
389
390impl fmt::Debug for RawValue {
391   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
392      fn dtable(f: &mut fmt::Formatter, dtable: &DispatchTable) -> fmt::Result {
393         let type_name = &dtable.pretty_name;
394         write!(f, "<[{type_name}]>")
395      }
396
397      unsafe {
398         match self.0.kind() {
399            ValueKind::Nil => f.write_str("nil"),
400            ValueKind::Boolean => write!(f, "{}", self.0.get_boolean_unchecked()),
401            ValueKind::Number => write!(f, "{}", self.0.get_number_unchecked()),
402            ValueKind::String => write!(f, "{:?}", self.0.get_raw_string_unchecked().get().deref()),
403            ValueKind::Function => write!(
404               f,
405               "<func {:?}>",
406               self.0.get_raw_function_unchecked().get_raw()
407            ),
408            ValueKind::List => {
409               f.write_char('[')?;
410               let list = self.0.get_raw_list_unchecked();
411               let elements = list.get().as_slice();
412               for (i, element) in elements.iter().enumerate() {
413                  if i != 0 {
414                     f.write_str(", ")?;
415                  }
416                  fmt::Debug::fmt(element, f)?;
417               }
418               f.write_char(']')?;
419               Ok(())
420            }
421            ValueKind::Dict => {
422               let dict = self.0.get_raw_dict_unchecked();
423               let dict = dict.get();
424               if dict.is_empty() {
425                  f.write_str("[:]")?;
426               } else {
427                  f.write_char('[')?;
428                  for (i, (key, value)) in dict.iter().enumerate() {
429                     if i != 0 {
430                        f.write_str(", ")?;
431                     }
432                     fmt::Debug::fmt(&key, f)?;
433                     f.write_str(": ")?;
434                     fmt::Debug::fmt(&value, f)?;
435                  }
436                  f.write_char(']')?;
437               }
438               Ok(())
439            }
440            ValueKind::Struct => dtable(f, self.0.get_raw_struct_unchecked().get().dtable()),
441            ValueKind::Trait => dtable(f, self.0.get_raw_trait_unchecked().get().dtable()),
442            ValueKind::UserData => dtable(f, self.0.get_raw_user_data_unchecked().get().dtable()),
443         }
444      }
445   }
446}
447
448impl fmt::Display for RawValue {
449   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
450      unsafe {
451         match self.0.kind() {
452            ValueKind::String => write!(f, "{}", self.0.get_raw_string_unchecked().get()),
453            _ => fmt::Debug::fmt(&self, f),
454         }
455      }
456   }
457}
458
459pub trait UserData: Any {
460   /// Returns a GC reference to the user data's dispatch table.
461   fn dtable_gcraw(&self) -> GcRaw<DispatchTable>;
462
463   /// Returns the user data's dispatch table.
464   ///
465   /// # Safety
466   /// This is basically sugar for `dtable_gcraw().get()`, so all the footguns of [`GcRaw::get`]
467   /// apply.
468   unsafe fn dtable(&self) -> &DispatchTable {
469      self.dtable_gcraw().get()
470   }
471
472   /// Converts a reference to `UserData` to `Any`.
473   fn as_any(&self) -> &dyn Any;
474}