ayun_core/support/
container.rs1use crate::{error::ContainerError, traits::InstanceTrait, Closure, Instance, Result};
2use std::{
3 any::TypeId,
4 collections::HashMap,
5 sync::{Arc, OnceLock},
6};
7
8static CONTAINER: OnceLock<Container> = OnceLock::new();
9
10type InstanceClosures = Vec<(
11 String,
12 Closure<Result<(), ContainerError>>,
13 Closure<Result<(), ContainerError>>,
14)>;
15
16#[derive(Default)]
17pub struct Container {
18 facades: HashMap<TypeId, Instance>,
19 closures: InstanceClosures,
20}
21
22impl Container {
23 pub fn register<T: InstanceTrait>(&mut self) -> Result<(), ContainerError> {
24 let instance = Arc::new(T::register(self).map_err(|err| ContainerError::Register {
25 instance: T::name(),
26 source: Box::new(err),
27 })?);
28
29 self.facades.insert(TypeId::of::<T>(), instance);
30
31 self.closures
32 .push((T::name(), Arc::new(T::boot), Arc::new(T::cleanup)));
33
34 Ok(())
35 }
36
37 pub fn instances(&self) -> Vec<&String> {
38 self.closures.iter().map(|(name, _, _)| name).collect()
39 }
40
41 pub fn boot(self) -> Result<(), ContainerError> {
42 let container = CONTAINER.get_or_init(|| self);
43
44 for (name, boot, _) in &container.closures {
45 boot().map_err(|err| ContainerError::Boot {
46 instance: name.to_owned(),
47 source: Box::new(err),
48 })?
49 }
50
51 Ok(())
52 }
53
54 pub fn cleanup(&self) -> Result<(), ContainerError> {
55 for (name, _, cleaner) in &self.closures {
56 cleaner().map_err(|err| ContainerError::Clean {
57 instance: name.to_owned(),
58 source: Box::new(err),
59 })?
60 }
61
62 Ok(())
63 }
64
65 pub fn resolve<T: InstanceTrait>(&self) -> Result<&T, ContainerError> {
66 let instance = self
67 .facades
68 .get(&TypeId::of::<T>())
69 .and_then(|boxed| boxed.downcast_ref::<T>())
70 .ok_or(ContainerError::Resolve {
71 instance: T::name(),
72 })?;
73
74 Ok(instance)
75 }
76}
77
78pub fn app() -> &'static Container {
79 CONTAINER.get().expect("`Container` not initialized")
80}