diff --git a/src/mem/basic.rs b/src/mem/basic.rs index 0d8d495..32b504e 100644 --- a/src/mem/basic.rs +++ b/src/mem/basic.rs @@ -8,6 +8,7 @@ use crate::{ }; use std::{collections::HashMap, ptr::NonNull}; +#[derive(Default)] pub struct BasicGc { objects: Vec>>, strs: HashMap>, @@ -69,3 +70,33 @@ impl Intern for BasicGc { .or_insert_with(|| len) } } + +// TODO object cloning +// implementing `clone` is difficult without an ObjCtx, since Attrs has a pointer to itself. This +// pointer would need to be updated. +// +// This will probably require a custom `ObjClone` trait to achieve the desired behavior with a ctx +// object + +/* +#[test] +fn test_gc_clone() { + use crate::{obj::{attrs::AttrsBuilder, ctx::DefaultGc, Attrs, ObjCtx}}; + + let mut ctx = ObjCtx::new(DefaultGc::default()); + + let empty_attrs = Attrs::new(&mut ctx, Default::default()); + + let empty_sym = ctx.gc_mut().add_sym("empty"); + let attrs_source = AttrsBuilder::new(&mut ctx) + .attr_sym(empty_sym, empty_attrs.as_dyn()) + .finish(); + + let attrs_clone = ctx.gc_mut().cloned(attrs_source.borrow()); + + + assert!(!std::ptr::eq(attrs_source.as_ptr(), attrs_clone.as_ptr())); + + let empty1 = attrs_source.borrow().get(empty_sym).unwrap(); +} +*/ diff --git a/src/mem/gc.rs b/src/mem/gc.rs index 06df5c1..84c64a8 100644 --- a/src/mem/gc.rs +++ b/src/mem/gc.rs @@ -5,18 +5,14 @@ use crate::{ intern::Intern, } }; +use std::ptr::NonNull; pub trait Gc: Intern { fn alloc(&mut self, obj: O) -> ObjRef; fn add_obj(&mut self, owned: Box>); - fn mark(&mut self, alive: &[DynRef]) { - for obj in alive.iter() { - obj.borrow_mut().mark(); - } - } + fn mark(&mut self, alive: &[DynRef]); fn sweep(&mut self); } - diff --git a/src/obj/attrs.rs b/src/obj/attrs.rs index fa24d5b..505bcbf 100644 --- a/src/obj/attrs.rs +++ b/src/obj/attrs.rs @@ -4,19 +4,21 @@ use crate::{ }; use std::{ cell::Cell, + collections::BTreeMap, mem::MaybeUninit, ptr::{self, NonNull}, }; -#[derive(Clone)] +pub type AttrsMap = BTreeMap; + pub struct Attrs { - attrs: Vec<(Sym, DynRef)>, + attrs: AttrsMap, marked: Cell, this: ObjRef, } impl Attrs { - pub fn new(ctx: &mut ObjCtx) -> Self { + 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 @@ -31,19 +33,27 @@ impl Attrs { obj.assume_init() }; - let attrs = { + 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.clone() + obj_ref.this }; // Add the object to the allocator pool ctx.gc_mut().add_obj(obj); + obj_ref + } - attrs + 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() } } @@ -77,11 +87,59 @@ impl Obj for Attrs { } } +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 = Attrs::new(&mut ctx); + 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 + ), + ); + } } diff --git a/src/obj/ctx.rs b/src/obj/ctx.rs index 2ab87c6..6976069 100644 --- a/src/obj/ctx.rs +++ b/src/obj/ctx.rs @@ -1,12 +1,17 @@ -use crate::mem::{gc::Gc, BasicGc}; +use crate::{ + mem::{gc::Gc, ptr::DynRef, BasicGc}, + obj::Sym, +}; +use std::collections::BTreeMap; pub type DefaultGc = BasicGc; -pub struct ObjCtx +pub struct ObjCtx where G: Gc, { gc: G, + globals: BTreeMap, } impl ObjCtx @@ -14,13 +19,22 @@ where G: Gc, { pub fn new(gc: G) -> Self { - ObjCtx { gc } + ObjCtx { gc, globals: Default::default() } } - + pub fn gc(&self) -> &G { &self.gc } + pub fn gc_mut(&mut self) -> &mut G { &mut self.gc } + + pub fn globals(&self) -> &BTreeMap { + &self.globals + } + + pub fn globals_mut(&mut self) -> &mut BTreeMap { + &mut self.globals + } } diff --git a/src/obj/str.rs b/src/obj/str.rs index bf189c0..986b8a8 100644 --- a/src/obj/str.rs +++ b/src/obj/str.rs @@ -1,6 +1,6 @@ -use crate::obj::prelude::*; +use crate::obj::{attrs::AttrsBuilder, prelude::*}; use derivative::Derivative; -use std::{any::Any, cell::Cell}; +use std::{any::Any, cell::Cell, collections::BTreeMap}; pub type StrRef = ObjRef; @@ -18,14 +18,17 @@ pub struct Str { impl Str { pub fn new(ctx: &mut ObjCtx, contents: String) -> Self { - todo!() - /* Str { - attrs: Default::default(), + attrs: Self::type_attrs(ctx), contents, marked: Cell::new(false), } - */ + } + + fn type_attrs(ctx: &mut ObjCtx) -> ObjRef { + // TODO need global namespace + // TODO need upcast from dyn to static + todo!() } pub fn contents(&self) -> &String { diff --git a/src/obj/ty.rs b/src/obj/ty.rs index f969771..c04b4c9 100644 --- a/src/obj/ty.rs +++ b/src/obj/ty.rs @@ -1,9 +1,9 @@ -use crate::obj::prelude::*; +use crate::obj::{attrs::AttrsBuilder, prelude::*}; use std::cell::Cell; pub struct Ty { marked: Cell, - this: ObjRef, + attrs: ObjRef, } impl Ty {