Skip to main content

geam_core/host/
value.rs

1use crate::BitArrayValue;
2use ecow::EcoString;
3use num_bigint::BigInt;
4use std::marker::PhantomData;
5
6/// A call-scoped value whose concrete runtime family is selected by `Type`.
7///
8/// This handle is used for generic parameters and cannot outlive its active
9/// [`crate::HostCall`].
10pub struct HostValue<'call, Type> {
11    pub(crate) token: HostValueToken,
12    marker: PhantomData<&'call Type>,
13}
14
15/// A call-scoped Gleam list with the statically declared `Item` ABI type.
16pub struct HostList<'call, Item> {
17    pub(crate) token: HostListToken,
18    marker: PhantomData<&'call Item>,
19}
20
21/// A call-scoped Gleam tuple described by a recursive host type sequence.
22pub struct HostTuple<'call, Elements> {
23    pub(crate) token: HostTupleToken,
24    marker: PhantomData<&'call Elements>,
25}
26
27/// A call-scoped ordinary Gleam custom value with a validated custom schema.
28pub struct HostCustom<'call, Custom> {
29    pub(crate) token: HostCustomToken,
30    marker: PhantomData<&'call Custom>,
31}
32
33/// A call-scoped external Gleam value with profile-owned Rust storage.
34///
35/// ```compile_fail
36/// use geam_core::HostExternal;
37///
38/// fn escape<'call, Type>(
39///     value: HostExternal<'call, Type>,
40/// ) -> HostExternal<'static, Type> {
41///     value
42/// }
43/// ```
44pub struct HostExternal<'call, Type> {
45    pub(crate) token: HostExternalToken,
46    marker: PhantomData<&'call Type>,
47}
48
49/// A call-scoped Gleam function with an exact typed signature.
50///
51/// The callable belongs to one active [`crate::HostCall`] and cannot be
52/// retained after that invocation.
53///
54/// ```compile_fail
55/// use geam_core::{HostCallable, HostTypeListEnd};
56/// use num_bigint::BigInt;
57///
58/// fn escape<'call>(
59///     callable: HostCallable<'call, HostTypeListEnd, BigInt>,
60/// ) -> HostCallable<'static, HostTypeListEnd, BigInt> {
61///     callable
62/// }
63/// ```
64pub struct HostCallable<'call, Arguments, Return> {
65    pub(crate) token: HostFunctionToken,
66    marker: PhantomData<&'call (Arguments, Return)>,
67}
68
69/// A typed value completed by one active [`crate::HostCall`].
70///
71/// The completion cannot be retained beyond the invocation that owns its
72/// runtime value tokens.
73///
74/// ```compile_fail
75/// use geam_core::HostCallCompletion;
76/// use num_bigint::BigInt;
77///
78/// fn escape<'call>(
79///     completion: HostCallCompletion<'call, BigInt>,
80/// ) -> HostCallCompletion<'static, BigInt> {
81///     completion
82/// }
83/// ```
84pub struct HostCallCompletion<'call, Return> {
85    pub(crate) token: HostValueToken,
86    call: PhantomData<&'call mut ()>,
87    return_: PhantomData<fn() -> Return>,
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
91pub(crate) struct HostValueToken {
92    pub family: HostValueFamily,
93    pub index: usize,
94}
95
96#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
97pub(crate) enum HostValueFamily {
98    Int,
99    Float,
100    String,
101    BitArray,
102    UtfCodepoint,
103    Bool,
104    Nil,
105    List,
106    Tuple,
107    Custom,
108    External,
109    Function,
110    SymbolicFunction,
111}
112
113#[derive(Debug, Clone, Copy, PartialEq, Eq)]
114pub(crate) enum HostListToken {
115    Parameter(usize),
116    Stored(usize),
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120pub(crate) struct HostTupleToken(pub usize);
121
122#[derive(Debug, Clone, Copy, PartialEq, Eq)]
123pub(crate) struct HostCustomToken(pub usize);
124
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
126pub(crate) struct HostExternalToken(pub usize);
127
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129pub(crate) struct HostFunctionToken(pub usize);
130
131#[derive(Debug, PartialEq)]
132pub(crate) enum HostScopedValue {
133    Int(BigInt),
134    Float(f64),
135    String(EcoString),
136    BitArray(BitArrayValue),
137    UtfCodepoint(char),
138    Bool(bool),
139    Nil,
140    Value(HostValueToken),
141    List(HostListToken),
142    Tuple(HostTupleToken),
143    Custom(HostCustomToken),
144    External(HostExternalToken),
145    Function(HostFunctionToken),
146}
147
148impl<'call, Type> HostValue<'call, Type> {
149    pub(crate) fn new(token: HostValueToken) -> Self {
150        Self {
151            token,
152            marker: PhantomData,
153        }
154    }
155}
156
157impl<Type> Clone for HostValue<'_, Type> {
158    fn clone(&self) -> Self {
159        *self
160    }
161}
162
163impl<Type> Copy for HostValue<'_, Type> {}
164
165impl<'call, Item> HostList<'call, Item> {
166    pub(crate) fn new(token: HostListToken) -> Self {
167        Self {
168            token,
169            marker: PhantomData,
170        }
171    }
172}
173
174impl<Item> Clone for HostList<'_, Item> {
175    fn clone(&self) -> Self {
176        *self
177    }
178}
179
180impl<Item> Copy for HostList<'_, Item> {}
181
182impl<'call, Elements> HostTuple<'call, Elements> {
183    pub(crate) fn new(token: HostTupleToken) -> Self {
184        Self {
185            token,
186            marker: PhantomData,
187        }
188    }
189}
190
191impl<Elements> Clone for HostTuple<'_, Elements> {
192    fn clone(&self) -> Self {
193        *self
194    }
195}
196
197impl<Elements> Copy for HostTuple<'_, Elements> {}
198
199impl<'call, Custom> HostCustom<'call, Custom> {
200    pub(crate) fn new(token: HostCustomToken) -> Self {
201        Self {
202            token,
203            marker: PhantomData,
204        }
205    }
206}
207
208impl<Custom> Clone for HostCustom<'_, Custom> {
209    fn clone(&self) -> Self {
210        *self
211    }
212}
213
214impl<Custom> Copy for HostCustom<'_, Custom> {}
215
216impl<'call, Type> HostExternal<'call, Type> {
217    pub(crate) fn new(token: HostExternalToken) -> Self {
218        Self {
219            token,
220            marker: PhantomData,
221        }
222    }
223}
224
225impl<Type> Clone for HostExternal<'_, Type> {
226    fn clone(&self) -> Self {
227        *self
228    }
229}
230
231impl<Type> Copy for HostExternal<'_, Type> {}
232
233impl<'call, Arguments, Return> HostCallable<'call, Arguments, Return> {
234    pub(crate) fn new(token: HostFunctionToken) -> Self {
235        Self {
236            token,
237            marker: PhantomData,
238        }
239    }
240}
241
242impl<Arguments, Return> Clone for HostCallable<'_, Arguments, Return> {
243    fn clone(&self) -> Self {
244        *self
245    }
246}
247
248impl<Arguments, Return> Copy for HostCallable<'_, Arguments, Return> {}
249
250impl<'call, Return> HostCallCompletion<'call, Return> {
251    pub(crate) fn new(token: HostValueToken) -> Self {
252        Self {
253            token,
254            call: PhantomData,
255            return_: PhantomData,
256        }
257    }
258}
259
260#[cfg(test)]
261mod tests {
262    use super::{
263        HostCallable, HostCustom, HostCustomToken, HostExternal, HostExternalToken,
264        HostFunctionToken, HostList, HostListToken, HostTuple, HostTupleToken, HostValue,
265        HostValueFamily, HostValueToken,
266    };
267
268    #[test]
269    fn scoped_handles_preserve_only_the_call_owned_token() {
270        fn clone_handle<Handle: Clone>(handle: &Handle) -> Handle {
271            handle.clone()
272        }
273
274        let value = HostValue::<bool>::new(HostValueToken {
275            family: HostValueFamily::Bool,
276            index: 1,
277        });
278        let list = HostList::<bool>::new(HostListToken::Stored(2));
279        let tuple = HostTuple::<bool>::new(HostTupleToken(3));
280        let custom = HostCustom::<bool>::new(HostCustomToken(4));
281        let external = HostExternal::<bool>::new(HostExternalToken(5));
282        let callable = HostCallable::<bool, bool>::new(HostFunctionToken(6));
283        let copied = value;
284        let cloned_value = clone_handle(&value);
285        let cloned_list = clone_handle(&list);
286        let cloned_tuple = clone_handle(&tuple);
287        let cloned_custom = clone_handle(&custom);
288        let cloned_external = clone_handle(&external);
289        let cloned_callable = clone_handle(&callable);
290
291        assert_eq!(
292            value.token,
293            HostValueToken {
294                family: HostValueFamily::Bool,
295                index: 1,
296            },
297        );
298        assert_eq!(copied.token, value.token);
299        assert_eq!(cloned_value.token, value.token);
300        assert_eq!(list.token, HostListToken::Stored(2));
301        assert_eq!(cloned_list.token, list.token);
302        assert_eq!(tuple.token, HostTupleToken(3));
303        assert_eq!(cloned_tuple.token, tuple.token);
304        assert_eq!(custom.token, HostCustomToken(4));
305        assert_eq!(cloned_custom.token, custom.token);
306        assert_eq!(external.token, HostExternalToken(5));
307        assert_eq!(cloned_external.token, external.token);
308        assert_eq!(callable.token, HostFunctionToken(6));
309        assert_eq!(cloned_callable.token, callable.token);
310    }
311}