use crate::{ mem::ptr::{DynRef, ObjCell}, obj::prelude::*, }; use std::{ cell::Cell, collections::BTreeMap, mem::MaybeUninit, ptr::{self, NonNull}, }; pub type AttrsMap = BTreeMap; pub struct Attrs { attrs: AttrsMap, marked: Cell, this: ObjRef, } impl Attrs { pub fn new(ctx: &mut ObjCtx, attrs: BTreeMap) -> ObjRef { let obj: Box> = unsafe { let mut obj: Box>> = Box::new_uninit(); // maybe UB? taking away the uninit right before it's initialized may be bad let this = &*obj as *const _ as *const ObjCell; obj.as_mut_ptr().write(ObjCell::new(Attrs { attrs: Default::default(), marked: Cell::new(false), this: ObjRef::new(NonNull::new(this as *mut _).unwrap()), })); obj.assume_init() }; let obj_ref = { let obj_ref: &Attrs = &obj.borrow(); assert!( ptr::eq(&*obj as *const _, obj_ref.this.as_ptr()), "Attr 'this' member does not point to itself" ); obj_ref.this }; // Add the object to the allocator pool ctx.gc_mut().add_obj(obj); obj_ref } pub fn insert(&mut self, sym: Sym, value: DynRef) -> Option { self.attrs.insert(sym, value) } pub fn get(&self, sym: Sym) -> Option { dbg!(&self.attrs); self.attrs.get(&dbg!(sym)).copied() } } impl Obj for Attrs { fn attrs(&self) -> ObjRef { self.this } fn is_marked(&self) -> bool { self.marked.get() } fn mark(&self) { if self.is_marked() { return; } self.marked.set(true); self.attrs.iter().for_each(|(_, v)| v.borrow().mark()); } fn unmark(&self) { if !self.is_marked() { return; } self.marked.set(false); self.attrs.iter().for_each(|(_, v)| v.borrow().unmark()); } fn as_any(&self) -> &dyn std::any::Any { self } } pub struct AttrsBuilder<'ctx> { ctx: &'ctx mut ObjCtx, attrs: AttrsMap, } impl<'ctx> AttrsBuilder<'ctx> { pub fn new(ctx: &'ctx mut ObjCtx) -> Self { Self::with_base(ctx, Default::default()) } pub fn with_base(ctx: &'ctx mut ObjCtx, attrs: AttrsMap) -> Self { AttrsBuilder { attrs, ctx, } } pub fn attr(mut self, symbol_name: &str, value: DynRef) -> Self { let sym = self.ctx.gc_mut().add_sym(symbol_name); self.attr_sym(sym, value) } pub fn attr_sym(mut self, sym: Sym, value: DynRef) -> Self { self.attrs.insert(sym, value); self } pub fn finish(self) -> ObjRef { let Self { ctx, attrs } = self; Attrs::new(ctx, attrs) } } #[test] fn test_attrs_new() { use crate::mem::BasicGc; let mut ctx = ObjCtx::new(BasicGc::default()); let attrs_ref = Attrs::new(&mut ctx, Default::default()); { let mut attrs = attrs_ref.borrow_mut(); let sym = ctx.gc_mut().add_sym("symbol"); attrs.insert(sym, attrs_ref.as_dyn()); assert!( ptr::eq( dbg!(attrs.get(sym).unwrap().as_ptr()), dbg!(attrs_ref.as_dyn().as_ptr()) // ^ as_dyn() is important here - this will cause the test to fail // otherwise ), ); } }