1use std::any::Any;
2use std::marker::PhantomData;
3
4use wasmtime::component::{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
105#[doc(hidden)]
107pub struct FactorInitContext<'a, T, G> {
108 pub linker: &'a mut Linker<T>,
109 pub _marker: PhantomData<G>,
110}
111
112#[doc(hidden)]
114pub trait FactorField {
115 type State: crate::RuntimeFactorsInstanceState;
116 type Factor: Factor;
117
118 fn get(field: &mut Self::State)
119 -> (&mut FactorInstanceState<Self::Factor>, &mut ResourceTable);
120}
121
122impl<T, G> InitContext<G::Factor> for FactorInitContext<'_, T, G>
123where
124 G: FactorField,
125 T: AsInstanceState<G::State> + Send + 'static,
126{
127 type StoreData = T;
128
129 fn linker(&mut self) -> &mut Linker<Self::StoreData> {
130 self.linker
131 }
132
133 fn get_data_with_table(
134 store: &mut Self::StoreData,
135 ) -> (&mut FactorInstanceState<G::Factor>, &mut ResourceTable) {
136 G::get(store.as_instance_state())
137 }
138}
139
140pub struct ConfigureAppContext<'a, T: RuntimeFactors, F: Factor> {
141 app: &'a App,
142 app_state: &'a T::AppState,
143 runtime_config: Option<F::RuntimeConfig>,
144}
145
146impl<'a, T: RuntimeFactors, F: Factor> ConfigureAppContext<'a, T, F> {
147 #[doc(hidden)]
148 pub fn new(
149 app: &'a App,
150 app_state: &'a T::AppState,
151 runtime_config: Option<F::RuntimeConfig>,
152 ) -> crate::Result<Self> {
153 Ok(Self {
154 app,
155 app_state,
156 runtime_config,
157 })
158 }
159
160 pub fn app(&self) -> &'a App {
162 self.app
163 }
164
165 pub fn app_state<U: Factor>(&self) -> crate::Result<&'a U::AppState> {
167 T::app_state::<U>(self.app_state).ok_or(Error::no_such_factor::<U>())
168 }
169
170 pub fn runtime_config(&self) -> Option<&F::RuntimeConfig> {
172 self.runtime_config.as_ref()
173 }
174
175 pub fn take_runtime_config(&mut self) -> Option<F::RuntimeConfig> {
177 self.runtime_config.take()
178 }
179}
180
181#[doc(hidden)]
182pub struct ConfiguredApp<T: RuntimeFactors> {
183 app: App,
184 app_state: T::AppState,
185}
186
187impl<T: RuntimeFactors> ConfiguredApp<T> {
188 #[doc(hidden)]
189 pub fn new(app: App, app_state: T::AppState) -> Self {
190 Self { app, app_state }
191 }
192
193 pub fn app(&self) -> &App {
195 &self.app
196 }
197
198 pub fn app_state<U: Factor>(&self) -> crate::Result<&U::AppState> {
200 T::app_state::<U>(&self.app_state).ok_or(Error::no_such_factor::<U>())
201 }
202}