1use crate::{
5 Filter,
6 context::Context,
7 function::{FunctionHandle, FunctionQuery, FunctionQueryParameter, Parameters},
8 registry::{Registry, RegistryHandle},
9 types::TypeQuery,
10};
11use intuicio_data::data_stack::DataStackPack;
12use std::{cell::RefCell, marker::PhantomData, sync::Arc};
13use typid::ID;
14
15thread_local! {
16 static GLOBAL_HOST_STACK: RefCell<Vec<(HostId, Host)>> = const{ RefCell::new(vec![]) };
18}
19
20pub type HostId = ID<Host>;
22
23#[derive(Clone)]
29pub struct HostProducer {
30 producer: Arc<Box<dyn Fn() -> Host + Send + Sync>>,
31}
32
33impl HostProducer {
34 pub fn new(f: impl Fn() -> Host + Send + Sync + 'static) -> Self {
36 Self {
37 producer: Arc::new(Box::new(f)),
38 }
39 }
40
41 pub fn produce(&self) -> Host {
43 (self.producer)()
44 }
45}
46
47pub struct Host {
56 context: Context,
57 registry: RegistryHandle,
58}
59
60impl Host {
61 pub fn new(context: Context, registry: RegistryHandle) -> Self {
63 Self { context, registry }
64 }
65
66 pub fn fork(&self) -> Self {
69 Self {
70 context: self.context.fork(),
71 registry: self.registry.clone(),
72 }
73 }
74
75 #[allow(clippy::result_large_err)]
81 pub fn push_global(self) -> Result<HostId, Self> {
82 GLOBAL_HOST_STACK.with(|host| match host.try_borrow_mut() {
83 Ok(mut stack) => {
84 let id = HostId::new();
85 stack.push((id, self));
86 Ok(id)
87 }
88 Err(_) => Err(self),
89 })
90 }
91
92 pub fn pop_global() -> Option<Self> {
94 GLOBAL_HOST_STACK.with(move |stack| Some(stack.try_borrow_mut().ok()?.pop()?.1))
95 }
96
97 pub fn remove_global(id: HostId) -> Option<Self> {
99 GLOBAL_HOST_STACK.with(move |stack| {
100 let mut stack = stack.try_borrow_mut().ok()?;
101 let index = stack.iter().position(|(host_id, _)| host_id == &id)?;
102 Some(stack.remove(index).1)
103 })
104 }
105
106 pub fn with_global<T>(f: impl FnOnce(&mut Self) -> T) -> Option<T> {
110 GLOBAL_HOST_STACK.with(move |stack| {
111 let mut stack = stack.try_borrow_mut().ok()?;
112 let host = &mut stack.last_mut()?.1;
113 Some(f(host))
114 })
115 }
116
117 pub fn context(&mut self) -> &mut Context {
119 &mut self.context
120 }
121
122 pub fn registry(&self) -> &Registry {
124 &self.registry
125 }
126
127 pub fn context_and_registry(&mut self) -> (&mut Context, &Registry) {
129 (&mut self.context, &self.registry)
130 }
131
132 pub fn find_function(
134 &self,
135 name: &str,
136 module_name: &str,
137 type_name: Option<&str>,
138 ) -> Option<FunctionHandle> {
139 self.registry.find_function(FunctionQuery {
140 name: Some(name.into()),
141 module_name: Filter::Matching(module_name.into()),
142 type_query: type_name
143 .map(|type_name| TypeQuery {
144 name: Some(type_name.into()),
145 ..Default::default()
146 })
147 .into(),
148 ..Default::default()
149 })
150 }
151
152 pub fn call_function<O: DataStackPack, I: DataStackPack>(
168 &'_ mut self,
169 name: &str,
170 module_name: &str,
171 type_name: Option<&str>,
172 ) -> Option<HostFunctionCall<'_, I, O>> {
173 let inputs_query = I::pack_types()
174 .into_iter()
175 .map(|type_hash| FunctionQueryParameter {
176 type_query: Some(TypeQuery {
177 type_hash: Some(type_hash),
178 ..Default::default()
179 }),
180 ..Default::default()
181 })
182 .collect::<Vec<_>>();
183 let outputs_query = O::pack_types()
184 .into_iter()
185 .map(|type_hash| FunctionQueryParameter {
186 type_query: Some(TypeQuery {
187 type_hash: Some(type_hash),
188 ..Default::default()
189 }),
190 ..Default::default()
191 })
192 .collect::<Vec<_>>();
193 let handle = self.registry.find_function(FunctionQuery {
194 name: Some(name.into()),
195 module_name: Filter::Matching(module_name.into()),
196 type_query: type_name
197 .map(|type_name| TypeQuery {
198 name: Some(type_name.into()),
199 ..Default::default()
200 })
201 .into(),
202 inputs: Parameters::Exact(inputs_query.into()),
203 outputs: Parameters::Exact(outputs_query.into()),
204 ..Default::default()
205 })?;
206 Some(HostFunctionCall {
207 context: &mut self.context,
208 registry: &self.registry,
209 handle,
210 _phantom: Default::default(),
211 })
212 }
213}
214
215pub struct HostFunctionCall<'a, I: DataStackPack, O: DataStackPack> {
217 context: &'a mut Context,
218 registry: &'a Registry,
219 handle: FunctionHandle,
220 _phantom: PhantomData<(I, O)>,
221}
222
223impl<I: DataStackPack, O: DataStackPack> HostFunctionCall<'_, I, O> {
224 pub fn run(self, inputs: I) -> O {
226 self.handle.call(self.context, self.registry, inputs, false)
227 }
228}