blackbox_core/
compiler.rs

1use std::collections::HashSet;
2
3use blackbox_cast::*;
4
5use crate::{
6    builder::{ModuleBuilder, ProviderBuilder},
7    container::Container,
8    factory::Factory,
9    injectable::IInjectable,
10    instance_wrapper::{ContextId, InquirerId, InstanceToken, Scope},
11    module::{Module, ModuleToken},
12    reference::Ref,
13    reference_mut::RefMut,
14};
15
16pub struct ProviderCompilerContext {
17    pub inquirer_id: InquirerId,
18    pub context_id: ContextId,
19}
20impl ProviderCompilerContext {
21    pub fn new(context_id: ContextId, inquirer_id: InquirerId) -> ProviderCompilerContext {
22        ProviderCompilerContext {
23            context_id,
24            inquirer_id,
25        }
26    }
27}
28
29pub trait ProviderCompiler {
30    fn __blackbox_build(provider_builder: Ref<ProviderBuilder>);
31}
32
33pub struct ModuleCompilerContext {
34    pub stack: HashSet<ModuleToken>,
35    pub current_depth: u32,
36}
37
38impl ModuleCompilerContext {
39    pub fn new() -> ModuleCompilerContext {
40        ModuleCompilerContext {
41            stack: HashSet::new(),
42            current_depth: 0,
43        }
44    }
45}
46
47pub trait ModuleCompiler {
48    fn __blackbox_build(module_builder: Ref<ModuleBuilder>);
49}
50
51pub fn make_instance<T: Factory + CastFrom>(
52    token: InstanceToken,
53    module: RefMut<Module>,
54    container: RefMut<Container>,
55    context: RefMut<ProviderCompilerContext>,
56) -> Ref<dyn IInjectable> {
57    let instance_wrapper = container
58        .as_ref()
59        .get_provider_in_module(&token, module.clone())
60        .expect(
61            format!(
62                "The {} provider in the {} module was not found",
63                &token,
64                &module.as_ref().get_token(),
65            )
66            .as_ref(),
67        );
68
69    let scope = instance_wrapper.as_ref().get_scope();
70
71    match scope {
72        Scope::Transient => {
73            let context_id = context.as_ref().context_id.clone();
74            let inquirer_id = context.as_ref().inquirer_id.clone();
75
76            if let Some(instance) = instance_wrapper
77                .as_ref()
78                .get_instance_by_inquirer_id(&inquirer_id, &context_id)
79            {
80                return instance;
81            }
82
83            let instance = T::__blackbox_create().cast::<dyn IInjectable>().unwrap();
84
85            instance_wrapper.as_mut().set_instance_by_inquirer_id(
86                inquirer_id,
87                context_id,
88                instance.clone(),
89            );
90
91            return instance;
92        }
93        Scope::Singleton => {
94            if let Some(instance) = instance_wrapper.as_ref().get_instance() {
95                return instance;
96            }
97
98            let instance = T::__blackbox_create().cast::<dyn IInjectable>().unwrap();
99
100            instance_wrapper.as_mut().set_instance(instance.clone());
101
102            return instance;
103        }
104        _ => {
105            panic!("Unknown provider scope");
106        }
107    }
108}
109
110pub fn get_instance<T: Factory + CastFrom>(
111    token: InstanceToken,
112    module: RefMut<Module>,
113    container: RefMut<Container>,
114    context: RefMut<ProviderCompilerContext>,
115) -> Ref<T> {
116    let instance_wrapper = container
117        .as_ref()
118        .get_provider_in_module(&token, module.clone())
119        .expect(
120            format!(
121                "The {} provider in the {} module was not found",
122                &token,
123                &module.as_ref().get_token(),
124            )
125            .as_ref(),
126        );
127
128    let scope = instance_wrapper.as_ref().get_scope();
129
130    match scope {
131        Scope::Transient => {
132            let context_id = context.as_ref().context_id.clone();
133            let inquirer_id = context.as_ref().inquirer_id.clone();
134
135            return instance_wrapper
136                .as_mut()
137                .get_instance_by_inquirer_id(&inquirer_id, &context_id)
138                .expect(
139                    format!(
140                        "The {} instance of the {} inquirer was not found",
141                        &token, &inquirer_id,
142                    )
143                    .as_ref(),
144                )
145                .cast::<T>()
146                .unwrap();
147        }
148        Scope::Singleton => {
149            return instance_wrapper
150                .as_mut()
151                .get_instance()
152                .expect(format!("The {} static instance was not found", &token,).as_ref())
153                .cast::<T>()
154                .unwrap();
155        }
156        _ => {
157            panic!("Unknown provider scope");
158        }
159    }
160}
161
162// 1. (build) Modules, Instance Wrappers (Host, Id, Token, Scope)
163// 2. (init) Creation of the instances (Static/Transient)
164// 3. (link) Linking refs