1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use {
    std::{
        any::TypeId,
        cell::RefCell,
        rc::Rc,
        collections::{
            BTreeSet,
            HashMap,
            hash_map::Entry
        }
    },
    crate::{
        makepad_derive_live::*,
        makepad_live_tokenizer::{LiveId},
        LiveType,
        live_ptr::LiveModuleId,
    }
};

#[derive(Clone)]
pub struct LiveComponentInfo {
    pub name: LiveId,
    pub module_id: LiveModuleId,
}

pub trait LiveComponentRegistry {
    fn type_id(&self) -> LiveType;
    fn get_component_info(&self, name: LiveId) -> Option<LiveComponentInfo>;
    fn component_type(&self) -> LiveId;
    fn get_module_set(&self, set: &mut BTreeSet<LiveModuleId>);
}

#[derive(Default, Clone)]
pub struct LiveComponentRegistries(pub Rc<RefCell<HashMap<LiveType, Box<dyn LiveComponentRegistry >> >>);

generate_ref_cast_api!(LiveComponentRegistry);

impl LiveComponentRegistries {
    pub fn find_component(&self, ty: LiveId, name: LiveId) -> Option<LiveComponentInfo> {
        let reg = self.0.borrow();
        for entry in reg.values() {
            if entry.component_type() == ty {
                return entry.get_component_info(name)
            }
        }
        None
    }
    
    pub fn new() -> Self {
        Self (Rc::new(RefCell::new(HashMap::new())))
    }
    
    pub fn get<T: 'static + LiveComponentRegistry>(&self) -> std::cell::Ref<'_, T> {
        std::cell::Ref::map(
            self.0.borrow(),
            | v | v
                .get(&TypeId::of::<T>()).unwrap()
                .cast::<T>().unwrap()
        )
    }
    
    pub fn get_or_create<T: 'static + Default + LiveComponentRegistry>(&self) -> std::cell::RefMut<'_, T>
    {
        let reg = self.0.borrow_mut();
        std::cell::RefMut::map(
            reg,
            | v |
            match v.entry(TypeId::of::<T>()) {
                Entry::Occupied(o) => o.into_mut(),
                Entry::Vacant(v) => v.insert(Box::<T>::default())
            }
            .cast_mut::<T>().unwrap()
        )
    }
}