1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
use std::cell::{Ref, RefCell, RefMut}; use std::collections::HashMap; use std::fmt; use std::hash::{Hash, Hasher}; use std::rc::Rc; use crate::eval::Env; use crate::objects::{Datum, Eval, Foolang, Object, Vtable}; use crate::unwind::Unwind; pub struct Dictionary { data: RefCell<HashMap<Object, Object>>, } impl Dictionary { pub fn borrow(&self) -> Ref<HashMap<Object, Object>> { self.data.borrow() } pub fn borrow_mut(&self) -> RefMut<HashMap<Object, Object>> { self.data.borrow_mut() } } impl PartialEq for Dictionary { fn eq(&self, other: &Self) -> bool { std::ptr::eq(self, other) } } impl Eq for Dictionary {} impl Hash for Dictionary { fn hash<H: Hasher>(&self, state: &mut H) { std::ptr::hash(self, state); } } impl fmt::Debug for Dictionary { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{{")?; let mut first = true; for (k, v) in self.borrow().iter() { if first { first = false; } else { write!(f, ", ")?; } write!(f, "{:?} -> {:?}", k, v)?; } write!(f, "}}") } } pub fn class_vtable() -> Vtable { let vt = Vtable::new("class Dictionary"); vt.add_primitive_method_or_panic("new", class_dictionary_new); vt } pub fn instance_vtable() -> Vtable { let vt = Vtable::new("Dictionary"); vt.add_primitive_method_or_panic("at:", dictionary_at); vt.add_primitive_method_or_panic("put:at:", dictionary_put_at); vt } pub fn into_dictionary(foolang: &Foolang, data: HashMap<Object, Object>) -> Object { Object { vtable: Rc::clone(&foolang.dictionary_vtable), datum: Datum::Dictionary(Rc::new(Dictionary { data: RefCell::new(data), })), } } pub fn as_dictionary<'a>(obj: &'a Object, ctx: &str) -> Result<&'a Dictionary, Unwind> { match &obj.datum { Datum::Dictionary(ref dict) => Ok(dict), _ => Unwind::error(&format!("{:?} is not a Dictionary in {}", obj, ctx)), } } fn class_dictionary_new(_receiver: &Object, _args: &[Object], env: &Env) -> Eval { let data = RefCell::new(HashMap::new()); Ok(Object { vtable: env.foo.dictionary_vtable.clone(), datum: Datum::Dictionary(Rc::new(Dictionary { data, })), }) } fn dictionary_at(receiver: &Object, args: &[Object], env: &Env) -> Eval { match receiver.as_dictionary("in Dictionary#at:")?.borrow().get(&args[0]) { Some(obj) => Ok(obj.clone()), None => Ok(env.foo.make_boolean(false)), } } fn dictionary_put_at(receiver: &Object, args: &[Object], _env: &Env) -> Eval { receiver .as_dictionary("in Dictionary#put:at:")? .borrow_mut() .insert(args[1].clone(), args[0].clone()); Ok(receiver.clone()) }