Skip to main content

geam_core/provider/
callback.rs

1use super::{ProviderConstructionRequirements, ProviderConstructions};
2use crate::{
3    HostCall, HostCallError, HostCallable, HostProfile, HostProvider, HostType, HostTypeSequence,
4};
5use std::marker::PhantomData;
6
7type CallbackContextMarker<Profile, Provider, Return> =
8    PhantomData<fn() -> (Profile, Provider, Return)>;
9
10/// A call-scoped Gleam function that may be invoked by an active provider call.
11///
12/// The macro replaces the placeholder context with one exact static callback
13/// codec. Opaque function values use [`super::Value`] instead when they only
14/// need to pass through without invocation.
15pub struct Callback<Signature, Context = MissingCallbackContext> {
16    context: Context,
17    signature: PhantomData<fn() -> Signature>,
18}
19
20#[doc(hidden)]
21pub struct MissingCallbackContext;
22
23/// Directional Rust and host conversion selected by one generated callback
24/// declaration.
25#[doc(hidden)]
26pub trait ProviderCallbackCodec<'call, Profile, Provider, Return>
27where
28    Profile: HostProfile,
29    Provider: HostProvider<Profile>,
30    Return: HostType,
31{
32    type HostArguments: HostTypeSequence;
33    type HostReturn: HostType;
34    type Arguments;
35    type Returned;
36    type Requirements: ProviderConstructionRequirements;
37
38    fn into_host_arguments(
39        arguments: Self::Arguments,
40        call: &mut HostCall<'call, Profile, Provider, Return>,
41        constructions: &ProviderConstructions<'call, Self::Requirements>,
42    ) -> <Self::HostArguments as HostTypeSequence>::Values<'call>;
43
44    fn from_host_return(
45        value: <Self::HostReturn as HostType>::Value<'call>,
46        call: &mut HostCall<'call, Profile, Provider, Return>,
47    ) -> Self::Returned;
48}
49
50/// Exact callable and construction proof generated for one callback argument.
51#[doc(hidden)]
52pub struct ProviderCallbackContext<'call, Profile, Provider, Return, Codec>
53where
54    Profile: HostProfile,
55    Provider: HostProvider<Profile>,
56    Return: HostType,
57    Codec: ProviderCallbackCodec<'call, Profile, Provider, Return>,
58{
59    callable: HostCallable<'call, Codec::HostArguments, Codec::HostReturn>,
60    constructions: ProviderConstructions<'call, Codec::Requirements>,
61    context: CallbackContextMarker<Profile, Provider, Return>,
62}
63
64impl<'call, Signature, Profile, Provider, Return, Codec>
65    Callback<Signature, ProviderCallbackContext<'call, Profile, Provider, Return, Codec>>
66where
67    Profile: HostProfile,
68    Provider: HostProvider<Profile>,
69    Return: HostType,
70    Codec: ProviderCallbackCodec<'call, Profile, Provider, Return>,
71{
72    #[doc(hidden)]
73    pub fn from_host(
74        callable: HostCallable<'call, Codec::HostArguments, Codec::HostReturn>,
75        constructions: ProviderConstructions<'call, Codec::Requirements>,
76    ) -> Self {
77        Self {
78            context: ProviderCallbackContext {
79                callable,
80                constructions,
81                context: PhantomData,
82            },
83            signature: PhantomData,
84        }
85    }
86
87    pub(crate) fn invoke(
88        self,
89        call: &mut HostCall<'call, Profile, Provider, Return>,
90        arguments: Codec::Arguments,
91    ) -> Result<Codec::Returned, HostCallError> {
92        let arguments = Codec::into_host_arguments(arguments, call, &self.context.constructions);
93        let returned = call.invoke(self.context.callable, arguments)?;
94        Ok(Codec::from_host_return(returned, call))
95    }
96}
97
98impl<'call, Profile, Provider, Return, Codec> Clone
99    for ProviderCallbackContext<'call, Profile, Provider, Return, Codec>
100where
101    Profile: HostProfile,
102    Provider: HostProvider<Profile>,
103    Return: HostType,
104    Codec: ProviderCallbackCodec<'call, Profile, Provider, Return>,
105{
106    fn clone(&self) -> Self {
107        *self
108    }
109}
110
111impl<'call, Profile, Provider, Return, Codec> Copy
112    for ProviderCallbackContext<'call, Profile, Provider, Return, Codec>
113where
114    Profile: HostProfile,
115    Provider: HostProvider<Profile>,
116    Return: HostType,
117    Codec: ProviderCallbackCodec<'call, Profile, Provider, Return>,
118{
119}
120
121impl<Signature, Context> Clone for Callback<Signature, Context>
122where
123    Context: Clone,
124{
125    fn clone(&self) -> Self {
126        Self {
127            context: self.context.clone(),
128            signature: PhantomData,
129        }
130    }
131}
132
133impl<Signature, Context> Copy for Callback<Signature, Context> where Context: Copy {}