vizia_core/systems/
binding.rs

1use crate::{binding::StoreId, model::ModelOrView, prelude::*};
2use hashbrown::{HashMap, HashSet};
3use std::any::TypeId;
4
5pub(crate) fn binding_system(cx: &mut Context) {
6    let mut observers: HashMap<Entity, (Entity, TypeId, StoreId)> = HashMap::new();
7
8    for (entity, stores) in cx.stores.iter_mut() {
9        for (store_id, store) in stores.iter() {
10            let model_id = store.source();
11
12            observers.extend(
13                store.observers().iter().map(|e| (*e, (*entity, model_id, store_id.clone()))),
14            );
15        }
16    }
17
18    if !observers.is_empty() {
19        // Sort observers into tree ordering.
20        let ordered_observers = cx
21            .tree
22            .into_iter()
23            .filter_map(|ent| observers.get(&ent).map(|e| (ent, e.clone())))
24            .collect::<Vec<_>>();
25
26        let mut updated_stores: HashSet<StoreId> = HashSet::new();
27
28        // Update observers in tree order.
29        for (observer, (source, model_id, store_id)) in ordered_observers.into_iter() {
30            // Skip observers that have been destroyed.
31            if !cx.entity_manager.is_alive(observer) {
32                continue;
33            }
34
35            if updated_stores.contains(&store_id) {
36                update_binding(cx, observer);
37            } else if let Some(store) =
38                cx.stores.get_mut(&source).and_then(|stores| stores.get_mut(&store_id))
39            {
40                let view = cx
41                    .views
42                    .get(&source)
43                    .filter(|view| view.id() == model_id)
44                    .map(|view| ModelOrView::View(view.as_ref()));
45
46                let model_or_view = if view.is_some() {
47                    view
48                } else {
49                    cx.models
50                        .get(&source)
51                        .and_then(|models| models.get(&model_id))
52                        .map(|model| ModelOrView::Model(model.as_ref()))
53                };
54
55                if let Some(model_or_view) = model_or_view {
56                    if store.update(model_or_view) {
57                        updated_stores.insert(store_id);
58                        update_binding(cx, observer);
59                    }
60                }
61            }
62        }
63    }
64}
65
66fn update_binding(cx: &mut Context, observer: Entity) {
67    if let Some(mut binding) = cx.bindings.remove(&observer) {
68        cx.with_current(observer, |cx| {
69            binding.update(cx);
70        });
71        cx.bindings.insert(observer, binding);
72    }
73}