use std::rc::Rc; use hashbrown::{HashMap, HashSet}; use derive_more::Constructor; use itertools::Itertools; use crate::error::Result; use crate::vm::{LetEnv, VM}; use super::super::public as p; use super::Value; #[repr(C)] #[derive(Debug, Default, Constructor, Clone, PartialEq)] pub struct AttrSet<'jit: 'vm, 'vm> { data: HashMap>, } impl<'jit, 'vm> From>> for AttrSet<'jit, 'vm> { fn from(data: HashMap>) -> Self { Self { data } } } impl<'jit: 'vm, 'vm> AttrSet<'jit, 'vm> { pub fn with_capacity(cap: usize) -> Self { AttrSet { data: HashMap::with_capacity(cap), } } pub fn push_attr_force(&mut self, sym: usize, val: Value<'jit, 'vm>) { self.data.insert(sym, val); } pub fn push_attr(&mut self, sym: usize, val: Value<'jit, 'vm>) { if self.data.get(&sym).is_some() { todo!() } self.data.insert(sym, val); } pub fn select(&self, sym: usize) -> Option> { self.data.get(&sym).cloned().map(|val| match val { Value::Builtins(x) => Value::AttrSet(x.upgrade().unwrap()), val => val }) } pub fn has_attr(&self, sym: usize) -> bool { self.data.get(&sym).is_some() } pub fn capture(&mut self, env: &Rc>) { self.data.iter().for_each(|(_, v)| match v.clone() { Value::Thunk(ref thunk) => { thunk.capture(env.clone()); } _ => (), }) } pub fn update(&mut self, other: &AttrSet<'jit, 'vm>) { for (k, v) in other.data.iter() { self.push_attr_force(k.clone(), v.clone()) } } pub fn as_inner(&self) -> &HashMap> { &self.data } pub fn from_inner(data: HashMap>) -> Self { Self { data } } pub fn force_deep(&mut self, vm: &'vm VM<'jit>) -> Result<()> { let mut map: Vec<_> = self .data .iter() .map(|(k, v)| (k.clone(), v.clone())) .collect(); for (_, v) in map.iter_mut() { v.force_deep(vm)?; } self.data = map.into_iter().collect(); Ok(()) } pub fn eq_impl(&self, other: &AttrSet<'jit, 'vm>, vm: &'vm VM<'jit>) -> bool { self.data.iter().len() == other.data.iter().len() && std::iter::zip( self.data.iter().sorted_by_key(|(k, _)| **k), self.data.iter().sorted_by_key(|(k, _)| **k), ) .all(|((_, v1), (_, v2))| v1.eq_impl(v2, vm)) } pub fn to_public(&self, vm: &'vm VM, seen: &mut HashSet>) -> p::Value { p::Value::AttrSet(p::AttrSet::new( self.data .iter() .map(|(&sym, value)| (vm.get_sym(sym), value.to_public(vm, seen))) .collect(), )) } }