Skip to main content

geam_core/host/external/
stored.rs

1use super::store::ExternalPayloadView;
2use crate::host::type_::HostTypeAt;
3use crate::host::{
4    HostCall, HostCallRuntime, HostProfile, HostProvider, HostType, HostTypeSequence,
5};
6use std::marker::PhantomData;
7use std::ops::Deref;
8
9/// A typed Gleam value retained by one external payload.
10///
11/// Stored values are created by [`HostExternalPayloadBuilder`] and restored
12/// through [`HostExternalPayloadView`]. They cannot be cloned or moved out of
13/// the shared payload view.
14///
15/// ```compile_fail
16/// use geam_core::HostStoredValue;
17/// use num_bigint::BigInt;
18///
19/// struct Payload {
20///     value: HostStoredValue<BigInt>,
21/// }
22///
23/// fn take(payload: &Payload) -> HostStoredValue<BigInt> {
24///     payload.value
25/// }
26/// ```
27///
28/// ```compile_fail
29/// use geam_core::{HostModule, HostStoredValue};
30/// use num_bigint::BigInt;
31///
32/// let _ = HostModule::new("host_support", "host/storage")
33///     .unwrap()
34///     .with_function(
35///         "inject",
36///         |value: HostStoredValue<BigInt>| -> BigInt {
37///             let _ = value;
38///             0.into()
39///         },
40///     );
41/// ```
42pub struct HostStoredValue<Type> {
43    pub(crate) value: crate::runtime::StoredRuntimeValue,
44    marker: PhantomData<fn() -> Type>,
45}
46
47/// A stored value selected by a stable external type-argument position.
48pub struct HostStoredType<Index>(PhantomData<Index>);
49
50/// The active-call builder used to retain Gleam values in a new payload.
51pub struct HostExternalPayloadBuilder<'runtime, Profile, Arguments>
52where
53    Profile: HostProfile,
54    Arguments: HostTypeSequence,
55{
56    pub(super) runtime: &'runtime mut dyn HostCallRuntime<Profile>,
57    arguments: PhantomData<Arguments>,
58}
59
60/// An immutable external payload view that can restore its retained values.
61///
62/// ```compile_fail
63/// use geam_core::{HostExternalPayloadView, HostTypeListEnd};
64///
65/// fn escape<'call, Payload>(
66///     view: HostExternalPayloadView<'call, Payload, HostTypeListEnd>,
67/// ) -> HostExternalPayloadView<'static, Payload, HostTypeListEnd> {
68///     view
69/// }
70/// ```
71pub struct HostExternalPayloadView<'call, Payload, Arguments>
72where
73    Arguments: HostTypeSequence,
74{
75    pub(super) value: ExternalPayloadView<Payload>,
76    call: PhantomData<&'call Arguments>,
77}
78
79impl<Type> HostStoredValue<Type> {
80    pub(crate) fn new(value: crate::runtime::StoredRuntimeValue) -> Self {
81        Self {
82            value,
83            marker: PhantomData,
84        }
85    }
86}
87
88impl<'runtime, Profile, Arguments> HostExternalPayloadBuilder<'runtime, Profile, Arguments>
89where
90    Profile: HostProfile,
91    Arguments: HostTypeSequence,
92{
93    pub(crate) fn new(runtime: &'runtime mut dyn HostCallRuntime<Profile>) -> Self {
94        Self {
95            runtime,
96            arguments: PhantomData,
97        }
98    }
99
100    /// Retains a value with one exact monomorphic host type.
101    pub fn store<Type>(&mut self, value: Type::Value<'_>) -> HostStoredValue<Type>
102    where
103        Type: HostType,
104    {
105        HostStoredValue::new(
106            self.runtime
107                .retain_stored(crate::host::type_::into_scoped::<Type>(value)),
108        )
109    }
110
111    /// Retains a generic value by its stable external type-argument position.
112    pub fn store_argument<Index>(
113        &mut self,
114        value: <<Arguments as HostTypeAt<Index>>::Type as HostType>::Value<'_>,
115    ) -> HostStoredValue<HostStoredType<Index>>
116    where
117        Arguments: HostTypeAt<Index>,
118    {
119        HostStoredValue::new(
120            self.runtime
121                .retain_stored(crate::host::type_::into_scoped::<
122                    <Arguments as HostTypeAt<Index>>::Type,
123                >(value)),
124        )
125    }
126}
127
128impl<'call, Payload, Arguments> HostExternalPayloadView<'call, Payload, Arguments>
129where
130    Arguments: HostTypeSequence,
131{
132    pub(crate) fn new(value: ExternalPayloadView<Payload>) -> Self {
133        Self {
134            value,
135            call: PhantomData,
136        }
137    }
138
139    /// Restores one monomorphic value selected from this payload.
140    pub fn restore<Profile, Provider, Return, Type>(
141        &self,
142        call: &mut HostCall<'call, Profile, Provider, Return>,
143        select: impl FnOnce(&Payload) -> &HostStoredValue<Type>,
144    ) -> Type::Value<'call>
145    where
146        Profile: HostProfile,
147        Provider: HostProvider<Profile>,
148        Return: HostType,
149        Type: HostType,
150    {
151        call.restore_stored::<Type, Type>(select(&self.value))
152    }
153
154    /// Restores one value selected by its external type-argument position.
155    pub fn restore_argument<Profile, Provider, Return, Index>(
156        &self,
157        call: &mut HostCall<'call, Profile, Provider, Return>,
158        select: impl FnOnce(&Payload) -> &HostStoredValue<HostStoredType<Index>>,
159    ) -> <<Arguments as HostTypeAt<Index>>::Type as HostType>::Value<'call>
160    where
161        Profile: HostProfile,
162        Provider: HostProvider<Profile>,
163        Return: HostType,
164        Arguments: HostTypeAt<Index>,
165    {
166        call.restore_stored::<<Arguments as HostTypeAt<Index>>::Type, _>(select(&self.value))
167    }
168}
169
170impl<Payload, Arguments> Deref for HostExternalPayloadView<'_, Payload, Arguments>
171where
172    Arguments: HostTypeSequence,
173{
174    type Target = Payload;
175
176    fn deref(&self) -> &Self::Target {
177        &self.value
178    }
179}