reactive_graph_plugin_api/
lib.rs

1#[cfg(feature = "json5")]
2pub use json5;
3pub use serde_json;
4pub use springtime_di;
5pub use springtime_di::Component;
6pub use springtime_di::component_alias;
7pub use springtime_di::injectable;
8pub use springtime_di::instance_provider::ComponentInstancePtr;
9pub use springtime_di::instance_provider::ErrorPtr;
10#[cfg(feature = "toml")]
11pub use toml;
12
13pub use crate::PluginLoadingError;
14pub use PluginActivationError;
15pub use PluginDeactivationError;
16pub use PluginUnloadingError;
17pub use behaviours::entities::entity_behaviour_registry::*;
18pub use behaviours::entities::entity_component_behaviour_registry::*;
19pub use behaviours::relations::relation_behaviour_registry::*;
20pub use behaviours::relations::relation_component_behaviour_registry::*;
21pub use error::activation::*;
22pub use error::hot_deploy::*;
23pub use error::lifecycle::*;
24pub use error::loading::*;
25pub use graphql::graphql_query_service::*;
26pub use graphql::http_body::HttpBody;
27pub use graphql::web_resource_manager::*;
28pub use graphql::web_resource_provider::*;
29pub use instances::entities::entity_instance_manager::*;
30pub use instances::flows::flow_instance_manager::*;
31pub use instances::relations::relation_instance_manager::*;
32pub use plugin::PLUGIN_NAME_PREFIX;
33pub use plugin::Plugin;
34pub use plugin_context::*;
35pub use plugin_declaration::*;
36pub use plugin_dependency::*;
37pub use plugin_state::PluginDeployError;
38pub use plugin_state::PluginDisableError;
39pub use plugin_state::PluginRefreshingState;
40pub use plugin_state::PluginResolveState;
41pub use plugin_state::PluginStartError;
42pub use plugin_state::PluginStartingState;
43pub use plugin_state::PluginState;
44pub use plugin_state::PluginStopError;
45pub use plugin_state::PluginStoppingState;
46pub use plugin_state::PluginUninstallError;
47pub use plugin_state::PluginUninstallingState;
48pub use reactive_graph_graph as model;
49pub use system::command_manager::*;
50pub use system::config_manager::*;
51pub use types::components::component_import_export_manager::*;
52pub use types::components::component_manager::*;
53pub use types::components::component_provider_registry::*;
54pub use types::entities::entity_type_import_export_manager::*;
55pub use types::entities::entity_type_manager::*;
56pub use types::entities::entity_type_provider_registry::*;
57pub use types::flows::flow_type_import_export_manager::*;
58pub use types::flows::flow_type_manager::*;
59pub use types::flows::flow_type_provider_registry::*;
60pub use types::relations::relation_type_import_export_manager::*;
61pub use types::relations::relation_type_manager::*;
62pub use types::relations::relation_type_provider_registry::*;
63pub use types::type_system_event_manager::*;
64
65pub use reactive_graph_type_system_api::TypeProvider;
66// TODO: pub use reactive_graph_type_system_api::*;
67
68pub mod behaviours;
69pub mod instances;
70pub mod types;
71
72pub mod system;
73
74pub mod embedded_asset_provider;
75pub mod error;
76pub mod graphql;
77pub mod plugin;
78pub mod plugin_context;
79pub mod plugin_declaration;
80pub mod plugin_dependency;
81pub mod plugin_state;
82
83pub static RUSTC_VERSION: &str = env!("RUSTC_VERSION");
84pub static PLUGIN_API_VERSION: &str = env!("CARGO_PKG_VERSION");
85
86#[macro_export]
87macro_rules! export_plugin {
88    () => {
89        $crate::export_plugin_constants!();
90        $crate::construct_plugin!();
91        $crate::register_plugin!();
92        $crate::plugin_dependencies!();
93        $crate::export_plugin_declaration!();
94    };
95    ({
96        "plugin": {
97            "name": $name: expr,
98            "description": $description: expr,
99            "version": $version: expr $(,)?
100        } $(,)?
101    }) => {
102        $crate::export_plugin_constants!(
103            "plugin": {
104                "name": $name,
105                "description": $description,
106                "version": $version,
107            },
108        );
109        $crate::construct_plugin!();
110        $crate::register_plugin!();
111        $crate::plugin_dependencies!();
112        $crate::export_plugin_declaration!();
113    };
114    ({
115        "dependencies": [
116            $({
117                "name": $plugin_name: expr,
118                "version": $version_range: expr $(,)?
119            } $(,)?)*
120        ]
121    }) => {
122        $crate::export_plugin_constants!();
123        $crate::construct_plugin!();
124        $crate::register_plugin!();
125        $crate::plugin_dependencies!(
126            "dependencies": [
127                $({
128                    "name": $plugin_name,
129                    "version": $version_range,
130                },)*
131            ],
132        );
133        $crate::export_plugin_declaration!();
134    };
135    ({
136        "plugin": {
137            "name": $name: expr,
138            "description": $description: expr,
139            "version": $version: expr $(,)?
140        },
141        "dependencies": [
142            $({
143                "name": $plugin_name: expr,
144                "version": $version_range: expr $(,)?
145            } $(,)?)*
146        ]
147        $(,)?
148    }) => {
149        $crate::export_plugin_constants!(
150            "plugin": {
151                "name": $name,
152                "description": $description,
153                "version": $version,
154            },
155        );
156        $crate::construct_plugin!();
157        $crate::register_plugin!();
158        $crate::plugin_dependencies!(
159            "dependencies": [
160                $({
161                    "name": $plugin_name,
162                    "version": $version_range,
163                },)*
164            ],
165        );
166        $crate::export_plugin_declaration!();
167    };
168}
169#[macro_export]
170macro_rules! export_plugin_constants {
171    () => {
172        /// The name of the plugin (CARGO_PKG_NAME).
173        pub static PLUGIN_NAME: &str = env!("CARGO_PKG_NAME");
174
175        /// The description of the plugin (CARGO_PKG_DESCRIPTION).
176        pub static PLUGIN_DESCRIPTION: &str = env!("CARGO_PKG_DESCRIPTION");
177
178        /// The version of the plugin (CARGO_PKG_VERSION).
179        pub static PLUGIN_VERSION: &str = env!("CARGO_PKG_VERSION");
180    };
181    (
182        "plugin": {
183            "name": $name: expr,
184            "description": $description: expr,
185            "version": $version: expr $(,)?
186        } $(,)?
187    ) => {
188        /// The name of the plugin (CARGO_PKG_NAME).
189        pub static PLUGIN_NAME: &str = $name;
190
191        /// The description of the plugin (CARGO_PKG_DESCRIPTION).
192        pub static PLUGIN_DESCRIPTION: &str = $description;
193
194        /// The version of the plugin (CARGO_PKG_VERSION).
195        pub static PLUGIN_VERSION: &str = $version;
196    };
197}
198
199#[macro_export]
200macro_rules! construct_plugin {
201    () => {
202        /// Static plugin context.
203        ///
204        /// This plugin context is created by construct_plugin before constructing
205        /// the dependency injection container.
206        pub static PLUGIN_CONTEXT: std::sync::OnceLock<std::sync::Arc<dyn $crate::PluginContext + Send + Sync>> = std::sync::OnceLock::new();
207
208        /// Returns the static plugin context if called after construct_plugin or an empty option if called before construct_plugin.
209        ///
210        /// ```
211        /// pub struct MyPluginImpl {
212        ///   #[component(default = "inject_plugin_context_checked")]
213        ///   context: Option<std::sync::Arc<dyn reactive_graph_plugin_api::PluginContext + Send + Sync>>,
214        /// }
215        /// ```
216        pub fn inject_plugin_context_checked() -> Option<std::sync::Arc<dyn $crate::PluginContext + Send + Sync>> {
217            PLUGIN_CONTEXT.get().cloned()
218        }
219
220        /// Returns the static plugin context.
221        ///
222        /// ```
223        /// pub struct MyPluginImpl {
224        ///   #[component(default = "inject_plugin_context")]
225        ///   context: std::sync::Arc<dyn reactive_graph_plugin_api::PluginContext + Send + Sync>,
226        /// }
227        /// ```
228        ///
229        /// # Panics
230        ///
231        /// Panics if the inject_plugin_context was called before construct_plugin!
232        ///
233        pub fn inject_plugin_context() -> std::sync::Arc<dyn $crate::PluginContext + Send + Sync> {
234            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
235                panic!("The plugin context is uninitialized!");
236            };
237            context
238        }
239
240        pub fn component_provider_registry() -> std::sync::Arc<dyn reactive_graph_plugin_api::ComponentProviderRegistry + Send + Sync> {
241            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
242                panic!("The plugin context is uninitialized!");
243            };
244            context.get_component_provider_registry()
245        }
246
247        pub fn entity_types_provider_registry() -> std::sync::Arc<dyn reactive_graph_plugin_api::EntityTypeProviderRegistry + Send + Sync> {
248            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
249                panic!("The plugin context is uninitialized!");
250            };
251            context.get_entity_type_provider_registry()
252        }
253
254        pub fn relation_types_provider_registry() -> std::sync::Arc<dyn reactive_graph_plugin_api::RelationTypeProviderRegistry + Send + Sync> {
255            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
256                panic!("The plugin context is uninitialized!");
257            };
258            context.get_relation_type_provider_registry()
259        }
260
261        pub fn flow_types_provider_registry() -> std::sync::Arc<dyn reactive_graph_plugin_api::FlowTypeProviderRegistry + Send + Sync> {
262            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
263                panic!("The plugin context is uninitialized!");
264            };
265            context.get_flow_type_provider_registry()
266        }
267
268        pub fn entity_behaviour_registry() -> std::sync::Arc<dyn reactive_graph_plugin_api::EntityBehaviourRegistry + Send + Sync> {
269            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
270                panic!("The plugin context is uninitialized!");
271            };
272            context.get_entity_behaviour_registry()
273        }
274
275        pub fn entity_component_behaviour_registry() -> std::sync::Arc<dyn reactive_graph_plugin_api::EntityComponentBehaviourRegistry + Send + Sync> {
276            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
277                panic!("The plugin context is uninitialized!");
278            };
279            context.get_entity_component_behaviour_registry()
280        }
281
282        pub fn relation_behaviour_registry() -> std::sync::Arc<dyn reactive_graph_plugin_api::RelationBehaviourRegistry + Send + Sync> {
283            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
284                panic!("The plugin context is uninitialized!");
285            };
286            context.get_relation_behaviour_registry()
287        }
288
289        pub fn relation_component_behaviour_registry() -> std::sync::Arc<dyn reactive_graph_plugin_api::RelationComponentBehaviourRegistry + Send + Sync> {
290            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
291                panic!("The plugin context is uninitialized!");
292            };
293            context.get_relation_component_behaviour_registry()
294        }
295
296        pub fn component_manager() -> std::sync::Arc<dyn reactive_graph_plugin_api::ComponentManager + Send + Sync> {
297            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
298                panic!("The plugin context is uninitialized!");
299            };
300            context.get_component_manager()
301        }
302
303        pub fn entity_type_manager() -> std::sync::Arc<dyn reactive_graph_plugin_api::EntityTypeManager + Send + Sync> {
304            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
305                panic!("The plugin context is uninitialized!");
306            };
307            context.get_entity_type_manager()
308        }
309
310        pub fn relation_type_manager() -> std::sync::Arc<dyn reactive_graph_plugin_api::RelationTypeManager + Send + Sync> {
311            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
312                panic!("The plugin context is uninitialized!");
313            };
314            context.get_relation_type_manager()
315        }
316
317        pub fn flow_type_manager() -> std::sync::Arc<dyn reactive_graph_plugin_api::FlowTypeManager + Send + Sync> {
318            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
319                panic!("The plugin context is uninitialized!");
320            };
321            context.get_flow_type_manager()
322        }
323
324        pub fn web_resource_manager() -> std::sync::Arc<dyn reactive_graph_plugin_api::WebResourceManager + Send + Sync> {
325            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
326                panic!("The plugin context is uninitialized!");
327            };
328            context.get_web_resource_manager()
329        }
330
331        pub fn config_manager() -> std::sync::Arc<dyn reactive_graph_plugin_api::ConfigManager + Send + Sync> {
332            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
333                panic!("The plugin context is uninitialized!");
334            };
335            context.get_config_manager()
336        }
337
338        pub fn entity_instance_manager() -> std::sync::Arc<dyn reactive_graph_plugin_api::EntityInstanceManager + Send + Sync> {
339            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
340                panic!("The plugin context is uninitialized!");
341            };
342            context.get_entity_instance_manager()
343        }
344
345        pub fn relation_instance_manager() -> std::sync::Arc<dyn reactive_graph_plugin_api::RelationInstanceManager + Send + Sync> {
346            let Some(context) = PLUGIN_CONTEXT.get().cloned() else {
347                panic!("The plugin context is uninitialized!");
348            };
349            context.get_relation_instance_manager()
350        }
351
352        /// Constructs the plugin and initializes the plugin context.
353        ///
354        /// This method guarantees that the plugin context is set before initializing the
355        /// dependency injection framework. After `PLUGIN_CONTEXT.set` has been called, it's
356        /// guaranteed that PLUGIN_CONTEXT has a value. See also the documentation of OnceLock::set.
357        ///
358        /// Returns an error if the plugin construction failed, by either:
359        /// - The dependency injection container failed to construct
360        /// - The dependency injection container doesn't contain a component of type Plugin
361        /// - A component has unsatisfied dependencies.
362        pub fn construct_plugin(
363            context: std::sync::Arc<dyn $crate::PluginContext + Send + Sync>,
364        ) -> Result<std::sync::Arc<dyn $crate::Plugin + Send + Sync>, $crate::PluginLoadingError> {
365            let _ = PLUGIN_CONTEXT.set(context);
366            // After set has been called, it's guaranteed that PLUGIN_CONTEXT has a value.
367            $crate::springtime_di::factory::ComponentFactoryBuilder::new()
368                // Propagate errors from the ComponentFactoryBuilder
369                .map_err($crate::PluginLoadingError::ComponentDefinitionRegistryError)
370                .map(|component_factory| component_factory.build())
371                .and_then(|mut component_factory| {
372                    // Get the
373                    $crate::springtime_di::instance_provider::TypedComponentInstanceProvider::primary_instance_typed::<dyn $crate::Plugin + Send + Sync>(
374                        &mut component_factory,
375                    )
376                    .map_err($crate::PluginLoadingError::ComponentInstanceProviderError)
377                })
378        }
379    };
380}
381
382#[macro_export]
383macro_rules! register_plugin {
384    () => {
385        /// The `register` method is
386        #[allow(improper_ctypes_definitions)]
387        extern "C" fn register(registrar: &mut dyn $crate::PluginRegistrar) -> Result<(), $crate::PluginLoadingError> {
388            if let Err(error) = log4rs::init_file("config/logging.toml", Default::default()) {
389                println!("Failed to configure logger in {}: {}", PLUGIN_NAME, error);
390            }
391            match construct_plugin(registrar.context()) {
392                Ok(plugin) => {
393                    registrar.register_plugin(Box::new(plugin));
394                    Ok(())
395                }
396                Err(e) => Err(e),
397            }
398        }
399    };
400}
401
402#[macro_export]
403macro_rules! get_context {
404    ($context: expr, $err: expr) => {
405        $context.clone().ok_or($err)?
406    };
407}
408
409pub mod prelude;
410
411#[cfg(test)]
412#[cfg(not(tarpaulin_include))]
413pub mod tests;