use crate::{ mem::ptr::{DynRef, ObjCell}, obj::prelude::*, }; use std::{ cell::Cell, mem::MaybeUninit, ptr::{self, NonNull}, }; #[derive(Clone)] pub struct Attrs { attrs: Vec<(Sym, DynRef)>, marked: Cell, this: ObjRef, } impl Attrs { pub fn new(ctx: &mut ObjCtx) -> Self { 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 attrs = { 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.clone() }; // Add the object to the allocator pool ctx.gc_mut().add_obj(obj); attrs } } 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 } } #[test] fn test_attrs_new() { use crate::mem::BasicGc; let mut ctx = ObjCtx::new(BasicGc::default()); let attrs = Attrs::new(&mut ctx); }