lucia_lang/objects/
registry.rs

1use std::fmt;
2
3use gc_arena::{Collect, DynamicRoot, DynamicRootSet, Mutation, Rootable};
4
5use crate::{
6    objects::{AnyCallback, AnyUserData, Closure, Function, GcError, Str, Table, Value},
7    Context,
8};
9
10#[derive(Clone)]
11pub struct StaticStr(pub DynamicRoot<Rootable![Str<'_>]>);
12
13impl fmt::Debug for StaticStr {
14    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15        f.debug_tuple("StaticStr").field(&self.0.as_ptr()).finish()
16    }
17}
18
19#[derive(Clone)]
20pub struct StaticTable(pub DynamicRoot<Rootable![Table<'_>]>);
21
22impl fmt::Debug for StaticTable {
23    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
24        f.debug_tuple("StaticTable")
25            .field(&self.0.as_ptr())
26            .finish()
27    }
28}
29
30#[derive(Clone)]
31pub struct StaticClosure(pub DynamicRoot<Rootable![Closure<'_>]>);
32
33impl fmt::Debug for StaticClosure {
34    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35        f.debug_tuple("StaticClosure")
36            .field(&self.0.as_ptr())
37            .finish()
38    }
39}
40
41#[derive(Clone)]
42pub struct StaticCallback(pub DynamicRoot<Rootable![AnyCallback<'_>]>);
43
44impl fmt::Debug for StaticCallback {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        f.debug_tuple("StaticCallback")
47            .field(&self.0.as_ptr())
48            .finish()
49    }
50}
51
52#[derive(Clone)]
53pub struct StaticUserData(pub DynamicRoot<Rootable![AnyUserData<'_>]>);
54
55impl fmt::Debug for StaticUserData {
56    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57        f.debug_tuple("StaticUserData")
58            .field(&self.0.as_ptr())
59            .finish()
60    }
61}
62
63#[derive(Debug, Clone)]
64pub enum StaticFunction {
65    Closure(StaticClosure),
66    Callback(StaticCallback),
67}
68
69impl From<StaticClosure> for StaticFunction {
70    fn from(closure: StaticClosure) -> Self {
71        Self::Closure(closure)
72    }
73}
74
75impl From<StaticCallback> for StaticFunction {
76    fn from(callback: StaticCallback) -> Self {
77        Self::Callback(callback)
78    }
79}
80
81#[derive(Clone)]
82pub struct StaticError(pub DynamicRoot<Rootable![GcError<'_>]>);
83
84impl fmt::Debug for StaticError {
85    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
86        f.debug_tuple("StaticError")
87            .field(&self.0.as_ptr())
88            .finish()
89    }
90}
91
92#[derive(Debug, Clone)]
93pub enum StaticValue {
94    Null,
95    Bool(bool),
96    Int(i64),
97    Float(f64),
98    Str(StaticStr),
99    Table(StaticTable),
100    Function(StaticFunction),
101    UserData(StaticUserData),
102    Error(StaticError),
103}
104
105impl From<bool> for StaticValue {
106    fn from(v: bool) -> StaticValue {
107        StaticValue::Bool(v)
108    }
109}
110
111impl From<i64> for StaticValue {
112    fn from(v: i64) -> StaticValue {
113        StaticValue::Int(v)
114    }
115}
116
117impl From<f64> for StaticValue {
118    fn from(v: f64) -> StaticValue {
119        StaticValue::Float(v)
120    }
121}
122
123impl From<StaticStr> for StaticValue {
124    fn from(v: StaticStr) -> StaticValue {
125        StaticValue::Str(v)
126    }
127}
128
129impl From<StaticTable> for StaticValue {
130    fn from(v: StaticTable) -> StaticValue {
131        StaticValue::Table(v)
132    }
133}
134
135impl From<StaticFunction> for StaticValue {
136    fn from(v: StaticFunction) -> StaticValue {
137        StaticValue::Function(v)
138    }
139}
140
141impl From<StaticClosure> for StaticValue {
142    fn from(v: StaticClosure) -> StaticValue {
143        StaticValue::Function(StaticFunction::Closure(v))
144    }
145}
146
147impl From<StaticCallback> for StaticValue {
148    fn from(v: StaticCallback) -> StaticValue {
149        StaticValue::Function(StaticFunction::Callback(v))
150    }
151}
152
153impl From<StaticUserData> for StaticValue {
154    fn from(v: StaticUserData) -> StaticValue {
155        StaticValue::UserData(v)
156    }
157}
158
159pub trait Singleton<'gc> {
160    fn create(ctx: Context<'gc>) -> Self;
161}
162
163impl<'gc, T: Default> Singleton<'gc> for T {
164    fn create(_: Context<'gc>) -> Self {
165        Self::default()
166    }
167}
168
169#[derive(Copy, Clone, Collect)]
170#[collect(no_drop)]
171pub struct Registry<'gc> {
172    roots: DynamicRootSet<'gc>,
173}
174
175impl<'gc> Registry<'gc> {
176    pub fn new(mc: &Mutation<'gc>) -> Self {
177        Self {
178            roots: DynamicRootSet::new(mc),
179        }
180    }
181
182    pub fn roots(&self) -> DynamicRootSet<'gc> {
183        self.roots
184    }
185
186    pub fn stash<R: Stashable<'gc>>(&self, mc: &Mutation<'gc>, r: R) -> R::Stashed {
187        r.stash(&self.roots, mc)
188    }
189
190    pub fn fetch<F: Fetchable<'gc>>(&self, f: &F) -> F::Fetched {
191        f.fetch(&self.roots)
192    }
193}
194
195pub trait Stashable<'gc> {
196    type Stashed;
197
198    fn stash(self, roots: &DynamicRootSet<'gc>, mc: &Mutation<'gc>) -> Self::Stashed;
199}
200
201pub trait Fetchable<'gc> {
202    type Fetched;
203
204    fn fetch(&self, roots: &DynamicRootSet<'gc>) -> Self::Fetched;
205}
206
207macro_rules! reg_type {
208    ($t:ident, $r:ident) => {
209        impl<'gc> Stashable<'gc> for $t<'gc> {
210            type Stashed = $r;
211
212            fn stash(self, roots: &DynamicRootSet<'gc>, mc: &Mutation<'gc>) -> Self::Stashed {
213                $r(roots.stash::<Rootable![$t<'_>]>(mc, self))
214            }
215        }
216    };
217}
218
219reg_type!(Str, StaticStr);
220reg_type!(Table, StaticTable);
221reg_type!(Closure, StaticClosure);
222reg_type!(AnyCallback, StaticCallback);
223reg_type!(GcError, StaticError);
224reg_type!(AnyUserData, StaticUserData);
225
226macro_rules! fetch_type {
227    ($r:ident, $t:ident) => {
228        impl<'gc> Fetchable<'gc> for $r {
229            type Fetched = $t<'gc>;
230
231            fn fetch(&self, roots: &DynamicRootSet<'gc>) -> Self::Fetched {
232                *roots.fetch::<Rootable![$t<'_>]>(&self.0)
233            }
234        }
235    };
236}
237
238fetch_type!(StaticStr, Str);
239fetch_type!(StaticTable, Table);
240fetch_type!(StaticClosure, Closure);
241fetch_type!(StaticCallback, AnyCallback);
242fetch_type!(StaticError, GcError);
243fetch_type!(StaticUserData, AnyUserData);
244
245impl<'gc> Stashable<'gc> for Function<'gc> {
246    type Stashed = StaticFunction;
247
248    fn stash(self, roots: &DynamicRootSet<'gc>, mc: &Mutation<'gc>) -> Self::Stashed {
249        match self {
250            Function::Closure(closure) => StaticFunction::Closure(closure.stash(roots, mc)),
251            Function::Callback(callback) => StaticFunction::Callback(callback.stash(roots, mc)),
252        }
253    }
254}
255
256impl<'gc> Fetchable<'gc> for StaticFunction {
257    type Fetched = Function<'gc>;
258
259    fn fetch(&self, roots: &DynamicRootSet<'gc>) -> Self::Fetched {
260        match self {
261            StaticFunction::Closure(closure) => Function::Closure(closure.fetch(roots)),
262            StaticFunction::Callback(callback) => Function::Callback(callback.fetch(roots)),
263        }
264    }
265}
266
267impl<'gc> Stashable<'gc> for Value<'gc> {
268    type Stashed = StaticValue;
269
270    fn stash(self, roots: &DynamicRootSet<'gc>, mc: &Mutation<'gc>) -> Self::Stashed {
271        match self {
272            Value::Null => StaticValue::Null,
273            Value::Bool(b) => StaticValue::Bool(b),
274            Value::Int(i) => StaticValue::Int(i),
275            Value::Float(n) => StaticValue::Float(n),
276            Value::Str(s) => StaticValue::Str(s.stash(roots, mc)),
277            Value::Table(t) => StaticValue::Table(t.stash(roots, mc)),
278            Value::Function(f) => StaticValue::Function(f.stash(roots, mc)),
279            Value::UserData(u) => StaticValue::UserData(u.stash(roots, mc)),
280            Value::Error(e) => StaticValue::Error(e.stash(roots, mc)),
281        }
282    }
283}
284
285impl<'gc> Fetchable<'gc> for StaticValue {
286    type Fetched = Value<'gc>;
287
288    fn fetch(&self, roots: &DynamicRootSet<'gc>) -> Self::Fetched {
289        match self {
290            StaticValue::Null => Value::Null,
291            StaticValue::Bool(b) => Value::Bool(*b),
292            StaticValue::Int(i) => Value::Int(*i),
293            StaticValue::Float(n) => Value::Float(*n),
294            StaticValue::Str(s) => Value::Str(s.fetch(roots)),
295            StaticValue::Table(t) => Value::Table(t.fetch(roots)),
296            StaticValue::Function(f) => Value::Function(f.fetch(roots)),
297            StaticValue::UserData(u) => Value::UserData(u.fetch(roots)),
298            StaticValue::Error(e) => Value::Error(e.fetch(roots)),
299        }
300    }
301}