From 76a9c2259e4138ca46726131f5a84a5221e59b38 Mon Sep 17 00:00:00 2001 From: Christian Lincoln Date: Wed, 7 Oct 2026 19:58:09 +0100 Subject: [PATCH] Refactoring traits for garbage collection. Incomplete. --- macros/src/lib.rs | 84 +++++----- src/gc.rs | 397 ++++++++++++++++++++++++---------------------- 2 files changed, 248 insertions(+), 233 deletions(-) diff --git a/macros/src/lib.rs b/macros/src/lib.rs index ac82e28..4fb4ff7 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1,56 +1,54 @@ extern crate proc_macro; -use proc_macro::{Delimiter, Group, Punct, Ident, TokenStream, TokenTree, Literal, Spacing, Span}; +use map::{DisplacementSet, MapEntry}; use proc_macro::token_stream::IntoIter; +use proc_macro::{Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; use std::iter::Peekable; -use map::{DisplacementSet, Equivalent, Hashed, Hashes, MapEntry, TableEntry}; type Tokens = Peekable; -fn brackets(stream: TokenStream) -> TokenStream { - TokenStream::from(TokenTree::Group(Group::new(Delimiter::Brace,stream))) -} - -fn entry(input: &mut Tokens) -> Option> { - if let Some(token) = input.peek() { - let index = match input.next() { // Take one literal as an index +fn entry(input: &mut Tokens) -> Option> { + if input.peek().is_some() { + let index = match input.next() { + // Take one literal as an index Some(TokenTree::Literal(literal)) => literal.to_string(), Some(_) => panic!("Expected literal index"), None => return None, }; - match input.next() { // Look for '=' in "=>" - Some(TokenTree::Punct(punct)) if punct.as_char() == '=' => {}, + match input.next() { + // Look for '=' in "=>" + Some(TokenTree::Punct(punct)) if punct.as_char() == '=' => {} _ => panic!("Expected '=>'"), }; - match input.next() { // Look for '>' in "=>" - Some(TokenTree::Punct(punct)) if punct.as_char() == '>' => {}, + match input.next() { + // Look for '>' in "=>" + Some(TokenTree::Punct(punct)) if punct.as_char() == '>' => {} _ => panic!("Expected '=>'"), }; let mut value = Vec::new(); let mut closure = false; - loop { // Accumulate value token stream until ',' is found + loop { + // Accumulate value token stream until ',' is found match input.next() { Some(TokenTree::Punct(punct)) if punct.as_char() == ',' && !closure => break, - Some(ref it@TokenTree::Punct(ref punct)) if punct.as_char() == '|' => { + Some(ref it @ TokenTree::Punct(ref punct)) if punct.as_char() == '|' => { value.push(it.clone()); closure = !closure - }, + } Some(it) => value.push(it), None => break, } } let mut value_stream = TokenStream::new(); value_stream.extend(value); - Some(MapEntry(Some(( - index, - value_stream, - )))) + Some(MapEntry(Some((index, value_stream)))) } else { None } } #[proc_macro] -pub fn map(input: TokenStream) -> TokenStream { // todo: only works for string literals right now +pub fn map(input: TokenStream) -> TokenStream { + // todo: only works for string literals right now let mut tokens = input.into_iter().peekable(); let mut entries = DisplacementSet::new(); while let Some(entry) = entry(&mut tokens) { @@ -62,34 +60,35 @@ pub fn map(input: TokenStream) -> TokenStream { // todo: only works for string l let mut inner = TokenStream::new(); inner.extend(vec![ TokenTree::Literal(Literal::string(entry.0.as_str())), - TokenTree::Punct(Punct::new(',',Spacing::Alone)), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), ]); inner.extend(entry.1); - let inner = TokenStream::from(TokenTree::Group(Group::new(Delimiter::Parenthesis,inner))); + let inner = + TokenStream::from(TokenTree::Group(Group::new(Delimiter::Parenthesis, inner))); let mut option = TokenStream::new(); option.extend(vec![ - TokenTree::Ident(Ident::new("Some",Span::mixed_site())), - TokenTree::Group(Group::new(Delimiter::Parenthesis,inner)) + TokenTree::Ident(Ident::new("Some", Span::mixed_site())), + TokenTree::Group(Group::new(Delimiter::Parenthesis, inner)), ]); option } else { - TokenStream::from(TokenTree::Ident(Ident::new("None",Span::mixed_site()))) + TokenStream::from(TokenTree::Ident(Ident::new("None", Span::mixed_site()))) }; let mut set_entry = TokenStream::new(); set_entry.extend(vec![ - TokenTree::Ident(Ident::new("entry",Span::mixed_site())), - TokenTree::Punct(Punct::new(':',Spacing::Alone)), - TokenTree::Ident(Ident::new("MapEntry",Span::mixed_site())), - TokenTree::Group(Group::new(Delimiter::Parenthesis,option)), - TokenTree::Punct(Punct::new(',',Spacing::Alone)), - TokenTree::Ident(Ident::new("home",Span::mixed_site())), - TokenTree::Punct(Punct::new(':',Spacing::Alone)), + TokenTree::Ident(Ident::new("entry", Span::mixed_site())), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), + TokenTree::Ident(Ident::new("MapEntry", Span::mixed_site())), + TokenTree::Group(Group::new(Delimiter::Parenthesis, option)), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + TokenTree::Ident(Ident::new("home", Span::mixed_site())), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), TokenTree::Literal(Literal::usize_unsuffixed(entry.home)), - TokenTree::Punct(Punct::new(',',Spacing::Alone)), - TokenTree::Ident(Ident::new("displacement",Span::mixed_site())), - TokenTree::Punct(Punct::new(':',Spacing::Alone)), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), + TokenTree::Ident(Ident::new("displacement", Span::mixed_site())), + TokenTree::Punct(Punct::new(':', Spacing::Alone)), TokenTree::Literal(Literal::usize_unsuffixed(entry.displacement as usize)), - TokenTree::Punct(Punct::new(',',Spacing::Alone)), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), ]); elements.extend(vec![ /*TokenTree::Ident(Ident::new("deimos",Span::mixed_site())), @@ -98,11 +97,10 @@ pub fn map(input: TokenStream) -> TokenStream { // todo: only works for string l TokenTree::Ident(Ident::new("map",Span::mixed_site())), TokenTree::Punct(Punct::new(':',Spacing::Joint)), TokenTree::Punct(Punct::new(':',Spacing::Joint)),*/ - TokenTree::Ident(Ident::new("Entry",Span::mixed_site())), - TokenTree::Group(Group::new(Delimiter::Brace,set_entry)), - TokenTree::Punct(Punct::new(',',Spacing::Alone)), + TokenTree::Ident(Ident::new("Entry", Span::mixed_site())), + TokenTree::Group(Group::new(Delimiter::Brace, set_entry)), + TokenTree::Punct(Punct::new(',', Spacing::Alone)), ]) } - let mut array = TokenStream::from(TokenTree::Group(Group::new(Delimiter::Bracket,elements))); - array -} \ No newline at end of file + TokenStream::from(TokenTree::Group(Group::new(Delimiter::Bracket, elements))) +} diff --git a/src/gc.rs b/src/gc.rs index 046101c..18cdbf4 100644 --- a/src/gc.rs +++ b/src/gc.rs @@ -1,307 +1,324 @@ -use std::hash::{DefaultHasher, Hash, Hasher}; -use std::marker::{PhantomData}; -use std::ops::{Deref, DerefMut}; use map::{Hashed, Hashes}; +use std::hash::{DefaultHasher, Hash, Hasher}; +use std::marker::PhantomData; +use std::ops::{Deref, DerefMut}; type Index = u32; pub struct FreeList { - items: Vec>>, - free: Vec, - count: u32, + items: Vec>>, + free: Vec, + _count: u32, } -#[derive(Clone,Debug)] +#[derive(Clone, Debug)] pub struct AnyId { - pub(crate) index: Index + pub(crate) index: Index, } impl PartialEq for AnyId { - fn eq(&self, other: &Self) -> bool { - self.index == other.index - } + fn eq(&self, other: &Self) -> bool { + self.index == other.index + } } impl From for Id { - fn from(value: AnyId) -> Self { - Id { - index: value.index, - phantom_data: PhantomData, + fn from(value: AnyId) -> Self { + Id { + index: value.index, + phantom_data: PhantomData, + } } - } } #[derive(Debug)] pub struct Id { - pub(crate) index: Index, - phantom_data: PhantomData, + pub(crate) index: Index, + phantom_data: PhantomData, } pub struct RefId<'a, T> { - pub id: Id, - it: &'a mut T + pub id: Id, + it: &'a mut T, } impl<'a, T> Deref for RefId<'a, T> { - type Target = T; + type Target = T; - fn deref(&self) -> &Self::Target { - self.it - } + fn deref(&self) -> &Self::Target { + self.it + } } impl<'a, T> DerefMut for RefId<'a, T> { - - fn deref_mut(&mut self) -> &mut Self::Target { - self.it - } + fn deref_mut(&mut self) -> &mut Self::Target { + self.it + } } impl From> for Id { - fn from(value: RefId) -> Self { - value.id - } + fn from(value: RefId) -> Self { + value.id + } } impl Clone for Id { - fn clone(&self) -> Self { - Id { - index: self.index, - phantom_data: PhantomData::default(), + fn clone(&self) -> Self { + Id { + index: self.index, + phantom_data: PhantomData::default(), + } } - } } impl PartialEq for Id { - fn eq(&self, other: &Self) -> bool { - self.index == other.index - } + fn eq(&self, other: &Self) -> bool { + self.index == other.index + } } impl Eq for Id {} impl Hash for Id { - fn hash(&self, state: &mut H) { - self.index.hash(state) - } + fn hash(&self, state: &mut H) { + self.index.hash(state) + } } impl Id { - pub fn maybe(self) -> MaybeId { - MaybeId(self) - } - pub fn any(self) -> AnyId { AnyId { - index: self.index - } } + pub fn maybe(self) -> MaybeId { + MaybeId(self) + } + pub fn any(self) -> AnyId { + AnyId { index: self.index } + } } #[derive(Debug)] pub struct MaybeId(Id); impl From> for MaybeId { - fn from(value: Id) -> Self { - MaybeId(value) - } + fn from(value: Id) -> Self { + MaybeId(value) + } } impl Clone for MaybeId { - fn clone(&self) -> Self { - if self.0.index != u32::MAX { - MaybeId(self.0.clone()) - } else { - MaybeId::NULL + fn clone(&self) -> Self { + if self.0.index != u32::MAX { + MaybeId(self.0.clone()) + } else { + MaybeId::NULL + } } - } } impl PartialEq for MaybeId { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } } impl MaybeId { - pub const NULL: MaybeId = MaybeId(Id { index: u32::MAX, phantom_data: PhantomData {}, }); - pub fn unwrap(self) -> Id { - if self.0.index == u32::MAX { - panic!() - } else { - self.0 + pub const NULL: MaybeId = MaybeId(Id { + index: u32::MAX, + phantom_data: PhantomData {}, + }); + pub fn unwrap(self) -> Id { + if self.0.index == u32::MAX { + panic!() + } else { + self.0 + } } - } - pub fn exists(&self) -> Option> { - if self.0.index == u32::MAX { - None - } else { - Some(self.0.clone()) + pub fn exists(&self) -> Option> { + if self.0.index == u32::MAX { + None + } else { + Some(self.0.clone()) + } } - } } impl Default for FreeList { - fn default() -> Self { - Self::new() - } + fn default() -> Self { + Self::new() + } } impl FreeList { - pub fn new() -> FreeList { - FreeList { - items: Vec::new(), - free: Vec::new(), - count: 0, + pub fn new() -> FreeList { + FreeList { + items: Vec::new(), + free: Vec::new(), + _count: 0, + } } - } - pub fn get(&mut self, id: &Id) -> &mut T { - &mut self.items[id.index as usize].as_mut().unwrap().it - } - pub fn get_ref(&mut self, id: Id) -> RefId<'_, T> { - let it = self.get(&id); - RefId { id, it } - } - pub fn remove(&mut self, id: &Id) -> T { - self.free.push(id.index); - self.items[id.index as usize].take().unwrap().it - } - pub fn make(&mut self, value: T) -> RefId<'_, T> { // todo: shouldn't panic if allocation fails - if let Some(free) = self.free.pop() { - self.items[free as usize] = Some(Header::new(value)); - RefId { - id: Id { - index: free, - phantom_data: PhantomData, - }, - it: &mut self.items[free as usize].as_mut().unwrap().it, - } - } else { - self.items.push(Some(Header::new(value))); - let index = (self.items.len() - 1) as Index; - RefId { - id: Id { - index, - phantom_data: PhantomData, - }, - it: &mut self.items[index as usize].as_mut().unwrap().it, - } + pub fn get(&mut self, id: &Id) -> &mut T { + &mut self.items[id.index as usize].as_mut().unwrap().it + } + pub fn get_ref(&mut self, id: Id) -> RefId<'_, T> { + let it = self.get(&id); + RefId { id, it } + } + pub fn remove(&mut self, id: &Id) -> T { + self.free.push(id.index); + self.items[id.index as usize].take().unwrap().it + } + pub fn make(&mut self, value: T) -> RefId<'_, T> { + // todo: shouldn't panic if allocation fails + if let Some(free) = self.free.pop() { + self.items[free as usize] = Some(Header::new(value)); + RefId { + id: Id { + index: free, + phantom_data: PhantomData, + }, + it: &mut self.items[free as usize].as_mut().unwrap().it, + } + } else { + self.items.push(Some(Header::new(value))); + let index = (self.items.len() - 1) as Index; + RefId { + id: Id { + index, + phantom_data: PhantomData, + }, + it: &mut self.items[index as usize].as_mut().unwrap().it, + } + } } - } } pub struct IdNode { - item: T, - next: MaybeId>, + item: T, + next: MaybeId>, } -impl Traverse for IdNode where C: Allocates { - fn traverse(id: &Id>, context: &mut C) { - if let Some(ref next) = context.freelist().get(&id).next.exists() { - IdNode::traverse(next,context) +impl Traverse for IdNode +where + C: Allocates, +{ + fn traverse(id: &Id>, context: &mut C) { + if let Some(ref next) = context.freelist().get(&id).next.exists() { + IdNode::traverse(next, context) + } } - } - - fn collect(self) { - todo!() - } } #[derive(Clone)] pub struct LinkedList { - first: MaybeId>, - count: Index, + first: MaybeId>, + count: Index, } impl Default for LinkedList { - fn default() -> Self { - LinkedList { - first: MaybeId::NULL, - count: 0, + fn default() -> Self { + LinkedList { + first: MaybeId::NULL, + count: 0, + } } - } } impl LinkedList { - pub fn new() -> LinkedList { - LinkedList { - first: MaybeId::NULL, - count: 0, - } - } - pub fn add(&mut self, list: &mut FreeNodeList, it: T) { - let old = std::mem::replace(&mut self.first,list.make(IdNode { - item: it, - next: MaybeId::NULL, - }).id.maybe()); - list.get(&self.first.clone().unwrap()).next = old; // todo: this is painful - self.count += 1; - } - pub fn remove(&mut self, list: &mut FreeNodeList, criteria: F) -> T where T: PartialEq, F: Fn(&T) -> bool { - // Find some occurrence of 'item' in the list, remove and restitch the list, returning its id - let mut maybe_last = MaybeId::NULL; - let mut maybe_this = self.first.clone(); - while let Some(this) = maybe_this.exists() { - let node = list.remove(&this); - let next = node.next.clone(); - if criteria(&node.item) { - self.count -= 1; - if let Some(last) = maybe_last.exists() { - list.get(&last).next = node.next.clone(); - } else { - self.first = node.next.clone(); + pub fn new() -> LinkedList { + LinkedList { + first: MaybeId::NULL, + count: 0, } - return node.item; - } - maybe_last = maybe_this; - maybe_this = next; } - panic!() - } + pub fn add(&mut self, list: &mut FreeNodeList, it: T) { + let old = std::mem::replace( + &mut self.first, + list.make(IdNode { + item: it, + next: MaybeId::NULL, + }) + .id + .maybe(), + ); + list.get(&self.first.clone().unwrap()).next = old; // todo: this is painful + self.count += 1; + } + pub fn remove(&mut self, list: &mut FreeNodeList, criteria: F) -> T + where + T: PartialEq, + F: Fn(&T) -> bool, + { + // Find some occurrence of 'item' in the list, remove and restitch the list, returning its id + let mut maybe_last = MaybeId::NULL; + let mut maybe_this = self.first.clone(); + while let Some(this) = maybe_this.exists() { + let node = list.remove(&this); + let next = node.next.clone(); + if criteria(&node.item) { + self.count -= 1; + if let Some(last) = maybe_last.exists() { + list.get(&last).next = node.next.clone(); + } else { + self.first = node.next.clone(); + } + return node.item; + } + maybe_last = maybe_this; + maybe_this = next; + } + panic!() + } } pub type FreeNodeList = FreeList>; #[derive(Clone, Debug, Copy)] enum State { - Cold, - Warm, + Cold, + _Warm, } #[derive(Debug, Clone)] struct Header { - state: State, - it: T, + _state: State, + it: T, } -impl Header where { - fn new(it: T) -> Header { - Header { - state: State::Cold, - it, +impl Header { + fn new(it: T) -> Header { + Header { + _state: State::Cold, + it, + } } - } } -pub trait Allocates where Self: Sized, T: Traverse { - fn collect(); - fn freelist<'a>(&'a mut self) -> &'a mut FreeList; +pub trait Allocates +where + Self: Sized, + T: Traverse, +{ + fn freelist<'a>(&'a mut self) -> &'a mut FreeList; + fn get(&mut self, id: &Id) -> &mut T { + self.freelist().get(id) + } } pub trait Traverse: Sized { - fn traverse(id: &Id, context: &mut C); - fn collect(self); + fn traverse(id: &Id, context: &mut C); + // fn collect(self); } impl Hashes for Id { - fn hashed(&self) -> Hashed { - let mut hasher = DefaultHasher::new(); - self.index.hash(&mut hasher); - hasher.finish() as Hashed - } + fn hashed(&self) -> Hashed { + let mut hasher = DefaultHasher::new(); + self.index.hash(&mut hasher); + hasher.finish() as Hashed + } } impl Hashes for AnyId { - fn hashed(&self) -> Hashed { - let mut hasher = DefaultHasher::new(); - self.index.hash(&mut hasher); - hasher.finish() as Hashed - } + fn hashed(&self) -> Hashed { + let mut hasher = DefaultHasher::new(); + self.index.hash(&mut hasher); + hasher.finish() as Hashed + } }