use std::cell::{Cell, UnsafeCell};
use super::RawValue;
use crate::ll::{bytecode::DispatchTable, error::LanguageErrorKind, gc::GcRaw};
#[repr(align(8))]
#[derive(Debug)]
pub struct Struct {
pub(crate) dtable: UnsafeCell<GcRaw<DispatchTable>>,
sealed: Cell<bool>,
fields: UnsafeCell<Vec<RawValue>>,
}
impl Struct {
pub fn new_type(dtable: GcRaw<DispatchTable>) -> Self {
Self {
dtable: UnsafeCell::new(dtable),
sealed: Cell::new(false),
fields: UnsafeCell::new(Vec::new()),
}
}
pub(crate) unsafe fn new_instance(&self, field_count: usize) -> Self {
Self {
dtable: UnsafeCell::new(self.dtable().instance.unwrap_unchecked()),
sealed: Cell::new(true),
fields: UnsafeCell::new(
std::iter::repeat(RawValue::from(())).take(field_count).collect(),
),
}
}
pub unsafe fn dtable<'a>(&self) -> &'a DispatchTable {
self.dtable.get().as_ref().unwrap_unchecked().get()
}
pub(crate) fn implement(&self, dtable: GcRaw<DispatchTable>) -> Result<(), LanguageErrorKind> {
if self.sealed.get() {
return Err(LanguageErrorKind::StructAlreadyImplemented);
}
unsafe { *self.dtable.get() = dtable }
self.sealed.set(true);
Ok(())
}
pub(crate) unsafe fn get_field(&self, index: usize) -> RawValue {
*(*self.fields.get()).get_unchecked(index)
}
pub(crate) unsafe fn set_field(&self, index: usize, value: RawValue) {
*(*self.fields.get()).get_unchecked_mut(index) = value;
}
pub(crate) unsafe fn fields(&self) -> impl Iterator<Item = RawValue> + '_ {
(*self.fields.get()).iter().copied()
}
}