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 107 108 109
use std::any::Any; use std::fmt; use std::marker::PhantomData; use std::sync::Mutex; use api::generic::A; use api::{Generic, RuntimeResult, Userdata, VmType, WithVM}; use base::types::{ArcType, Type}; use gc::{Gc, GcPtr, Move, Traverseable}; use thread::ThreadInternal; use value::{Cloner, Value}; use vm::Thread; use {ExternModule, Result}; pub struct Reference<T> { value: Mutex<Value>, thread: GcPtr<Thread>, _marker: PhantomData<T>, } impl<T> Userdata for Reference<T> where T: Any + Send + Sync, { fn deep_clone(&self, deep_cloner: &mut Cloner) -> Result<GcPtr<Box<Userdata>>> { let value = self.value.lock().unwrap(); let cloned_value = deep_cloner.deep_clone(&value)?; let data: Box<Userdata> = Box::new(Reference { value: Mutex::new(cloned_value), thread: unsafe { GcPtr::from_raw(deep_cloner.thread()) }, _marker: PhantomData::<A>, }); deep_cloner.gc().alloc(Move(data)) } } impl<T> fmt::Debug for Reference<T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "Ref({:?})", *self.value.lock().unwrap()) } } impl<T> Traverseable for Reference<T> { fn traverse(&self, gc: &mut Gc) { self.value.lock().unwrap().traverse(gc) } } impl<T> VmType for Reference<T> where T: VmType, T::Type: Sized, { type Type = Reference<T::Type>; fn make_type(vm: &Thread) -> ArcType { let env = vm.global_env().get_env(); let symbol = env.find_type_info("Ref").unwrap().name.clone(); let ctor = Type::ident(symbol); Type::app(ctor, collect![T::make_type(vm)]) } } fn set(r: &Reference<A>, a: Generic<A>) -> RuntimeResult<(), String> { unsafe { match r.thread.deep_clone_value(&r.thread, a.get_value()) { Ok(a) => { *r.value.lock().unwrap() = a; RuntimeResult::Return(()) } Err(err) => RuntimeResult::Panic(format!("{}", err)), } } } fn get(r: &Reference<A>) -> Generic<A> { Generic::from(r.value.lock().unwrap().clone()) } fn make_ref(a: WithVM<Generic<A>>) -> Reference<A> { unsafe { Reference { value: Mutex::new(a.value.get_value()), thread: GcPtr::from_raw(a.vm), _marker: PhantomData, } } } mod std { pub mod reference { pub use reference as prim; } } pub fn load(vm: &Thread) -> Result<ExternModule> { use self::std; let _ = vm.register_type::<Reference<A>>("Ref", &["a"]); ExternModule::new( vm, record!{ type Reference a => Reference<A>, (store "<-") => named_primitive!(2, "std.reference.prim.(<-)", std::reference::prim::set), load => named_primitive!(1, "std.reference.prim.load", std::reference::prim::get), (ref_ "ref") => named_primitive!(1, "std.reference.prim.ref", std::reference::prim::make_ref), }, ) }