1use std::any::Any;
2use std::marker::PhantomData;
3
4use wasmtime::component::{HasData, Linker, ResourceTable};
5
6use crate::{
7 prepare::FactorInstanceBuilder, App, AsInstanceState, Error, PrepareContext, RuntimeFactors,
8};
9
10pub trait Factor: Any + Sized {
12 type RuntimeConfig;
17
18 type AppState: Sync;
22
23 type InstanceBuilder: FactorInstanceBuilder;
25
26 fn init(&mut self, ctx: &mut impl InitContext<Self>) -> anyhow::Result<()> {
32 let _ = ctx;
33 Ok(())
34 }
35
36 fn configure_app<T: RuntimeFactors>(
52 &self,
53 ctx: ConfigureAppContext<T, Self>,
54 ) -> anyhow::Result<Self::AppState>;
55
56 fn prepare<T: RuntimeFactors>(
64 &self,
65 ctx: PrepareContext<T, Self>,
66 ) -> anyhow::Result<Self::InstanceBuilder>;
67}
68
69pub type FactorInstanceState<F> =
71 <<F as Factor>::InstanceBuilder as FactorInstanceBuilder>::InstanceState;
72
73pub trait InitContext<F: Factor> {
76 type StoreData: Send + 'static;
78
79 fn linker(&mut self) -> &mut Linker<Self::StoreData>;
81
82 fn get_data(store: &mut Self::StoreData) -> &mut FactorInstanceState<F> {
84 Self::get_data_with_table(store).0
85 }
86
87 fn get_data_with_table(
90 store: &mut Self::StoreData,
91 ) -> (&mut FactorInstanceState<F>, &mut ResourceTable);
92
93 fn link_bindings(
95 &mut self,
96 add_to_linker: impl Fn(
97 &mut Linker<Self::StoreData>,
98 fn(&mut Self::StoreData) -> &mut FactorInstanceState<F>,
99 ) -> anyhow::Result<()>,
100 ) -> anyhow::Result<()> {
101 add_to_linker(self.linker(), Self::get_data)
102 }
103}
104
105pub struct FactorData<F>(F);
108
109impl<F: Factor> HasData for FactorData<F> {
110 type Data<'a> = &'a mut FactorInstanceState<F>;
111}
112
113#[doc(hidden)]
115pub struct FactorInitContext<'a, T: 'static, G> {
116 pub linker: &'a mut Linker<T>,
117 pub _marker: PhantomData<G>,
118}
119
120#[doc(hidden)]
122pub trait FactorField {
123 type State: crate::RuntimeFactorsInstanceState;
124 type Factor: Factor;
125
126 fn get(field: &mut Self::State)
127 -> (&mut FactorInstanceState<Self::Factor>, &mut ResourceTable);
128}
129
130impl<T, G> InitContext<G::Factor> for FactorInitContext<'_, T, G>
131where
132 G: FactorField,
133 T: AsInstanceState<G::State> + Send + 'static,
134{
135 type StoreData = T;
136
137 fn linker(&mut self) -> &mut Linker<Self::StoreData> {
138 self.linker
139 }
140
141 fn get_data_with_table(
142 store: &mut Self::StoreData,
143 ) -> (&mut FactorInstanceState<G::Factor>, &mut ResourceTable) {
144 G::get(store.as_instance_state())
145 }
146}
147
148pub struct ConfigureAppContext<'a, T: RuntimeFactors, F: Factor> {
149 app: &'a App,
150 app_state: &'a T::AppState,
151 runtime_config: Option<F::RuntimeConfig>,
152}
153
154impl<'a, T: RuntimeFactors, F: Factor> ConfigureAppContext<'a, T, F> {
155 #[doc(hidden)]
156 pub fn new(
157 app: &'a App,
158 app_state: &'a T::AppState,
159 runtime_config: Option<F::RuntimeConfig>,
160 ) -> crate::Result<Self> {
161 Ok(Self {
162 app,
163 app_state,
164 runtime_config,
165 })
166 }
167
168 pub fn app(&self) -> &'a App {
170 self.app
171 }
172
173 pub fn app_state<U: Factor>(&self) -> crate::Result<&'a U::AppState> {
175 T::app_state::<U>(self.app_state).ok_or(Error::no_such_factor::<U>())
176 }
177
178 pub fn runtime_config(&self) -> Option<&F::RuntimeConfig> {
180 self.runtime_config.as_ref()
181 }
182
183 pub fn take_runtime_config(&mut self) -> Option<F::RuntimeConfig> {
185 self.runtime_config.take()
186 }
187}
188
189#[doc(hidden)]
190pub struct ConfiguredApp<T: RuntimeFactors> {
191 app: App,
192 app_state: T::AppState,
193}
194
195impl<T: RuntimeFactors> ConfiguredApp<T> {
196 #[doc(hidden)]
197 pub fn new(app: App, app_state: T::AppState) -> Self {
198 Self { app, app_state }
199 }
200
201 pub fn app(&self) -> &App {
203 &self.app
204 }
205
206 pub fn app_state<U: Factor>(&self) -> crate::Result<&U::AppState> {
208 T::app_state::<U>(&self.app_state).ok_or(Error::no_such_factor::<U>())
209 }
210}