mica_language/value/
structs.rs

1use std::cell::{Cell, UnsafeCell};
2
3use crate::bytecode::DispatchTable;
4use crate::common::ErrorKind;
5use crate::gc::GcRaw;
6
7use super::RawValue;
8
9/// The innards of a struct.
10///
11/// Note that both types and actual constructed structs use the same representation. The difference
12/// is that types do not contain associated fields (Mica does not have static fields.)
13#[repr(align(8))]
14pub struct Struct {
15   /// The disptach table of the struct. This may only be set once, and setting it seals the
16   /// struct.
17   pub(crate) dtable: UnsafeCell<GcRaw<DispatchTable>>,
18   sealed: Cell<bool>,
19   fields: UnsafeCell<Vec<RawValue>>,
20}
21
22impl Struct {
23   /// Creates a new `Struct` representing a type.
24   pub fn new_type(dtable: GcRaw<DispatchTable>) -> Self {
25      Self {
26         dtable: UnsafeCell::new(dtable),
27         sealed: Cell::new(false),
28         fields: UnsafeCell::new(Vec::new()),
29      }
30   }
31
32   /// Creates a new instance of this struct type.
33   pub(crate) unsafe fn new_instance(&self, field_count: usize) -> Self {
34      Self {
35         dtable: UnsafeCell::new(self.dtable().instance.unwrap_unchecked()),
36         sealed: Cell::new(true),
37         fields: UnsafeCell::new(std::iter::repeat(RawValue::from(())).take(field_count).collect()),
38      }
39   }
40
41   /// Returns a reference to the dispatch table of the struct.
42   ///
43   /// # Safety
44   ///
45   /// Note that the reference's lifetime does not match the struct's. This is because the reference
46   /// actually comes from the GC, but `Struct` does not have a lifetime parameter that would
47   /// signify that.
48   ///
49   /// Because the lifetime of the reference is not tracked, this function is unsafe.
50   pub unsafe fn dtable<'a>(&self) -> &'a DispatchTable {
51      self.dtable.get().as_ref().unwrap_unchecked().get()
52   }
53
54   /// Implements the struct with the given dispatch table.
55   pub(crate) fn implement(&self, dtable: GcRaw<DispatchTable>) -> Result<(), ErrorKind> {
56      if self.sealed.get() {
57         return Err(ErrorKind::StructAlreadyImplemented);
58      }
59      unsafe { *self.dtable.get() = dtable }
60      self.sealed.set(true);
61      Ok(())
62   }
63
64   /// Returns the value of a field.
65   ///
66   /// # Safety
67   /// This does not perform any borrow checks or bounds checks.
68   pub(crate) unsafe fn get_field(&self, index: usize) -> RawValue {
69      *(*self.fields.get()).get_unchecked(index)
70   }
71
72   /// Sets the value of a field.
73   ///
74   /// # Safety
75   /// This does not perform any borrow checks or bounds checks.
76   pub(crate) unsafe fn set_field(&self, index: usize, value: RawValue) {
77      *(*self.fields.get()).get_unchecked_mut(index) = value;
78   }
79
80   pub(crate) unsafe fn fields(&self) -> impl Iterator<Item = RawValue> + '_ {
81      (*self.fields.get()).iter().copied()
82   }
83}