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
use crate::real_std::{any::Any, fmt, marker::PhantomData, sync::Mutex};
use crate::api::generic::A;
use crate::api::{Generic, RuntimeResult, Unrooted, Userdata, VmType, WithVM};
use crate::base::types::{ArcType, Type};
use crate::gc::{Gc, GcPtr, Move, Traverseable};
use crate::thread::ThreadInternal;
use crate::value::{Cloner, Value};
use crate::vm::Thread;
use crate::{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> {
match r.thread.deep_clone_value(&r.thread, a.get_variant()) {
Ok(a) => {
*r.value.lock().unwrap() = a;
RuntimeResult::Return(())
}
Err(err) => RuntimeResult::Panic(format!("{}", err)),
}
}
fn get(r: &Reference<A>) -> Unrooted<A> {
Unrooted::from(r.value.lock().unwrap().clone())
}
fn make_ref(a: WithVM<Generic<A>>) -> Reference<A> {
unsafe {
Reference {
value: Mutex::new(a.value.get_variant().get_value()),
thread: GcPtr::from_raw(a.vm),
_marker: PhantomData,
}
}
}
mod std {
pub mod reference {
pub use crate::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 "<-") => primitive!(2, "std.reference.prim.(<-)", std::reference::prim::set),
load => primitive!(1, "std.reference.prim.load", std::reference::prim::get),
(ref_ "ref") => primitive!(1, "std.reference.prim.ref", std::reference::prim::make_ref),
},
)
}