vizia_core/binding/
binding_view.rs
1use hashbrown::{HashMap, HashSet};
2use std::any::TypeId;
3
4use crate::binding::{BasicStore, Store, StoreId};
5use crate::context::{CURRENT, MAPS, MAP_MANAGER};
6use crate::model::ModelOrView;
7use crate::prelude::*;
8
9pub struct Binding<L>
15where
16 L: Lens,
17{
18 entity: Entity,
19 lens: L,
20 #[allow(clippy::type_complexity)]
21 content: Option<Box<dyn Fn(&mut Context, L)>>,
22}
23
24impl<L> Binding<L>
25where
26 L: 'static + Lens<Source: 'static, Target: Data>,
27{
28 #[allow(clippy::new_ret_no_self)]
42 pub fn new<F>(cx: &mut Context, lens: L, builder: F)
43 where
44 F: 'static + Fn(&mut Context, L),
45 {
46 let id = cx.entity_manager.create();
47 let current = cx.current();
48 cx.tree.add(id, current).expect("Failed to add to tree");
49 cx.cache.add(id);
50 cx.style.add(id);
51 cx.tree.set_ignored(id, true);
52
53 let binding = Self { entity: id, lens, content: Some(Box::new(builder)) };
54
55 CURRENT.with_borrow_mut(|f| *f = id);
56
57 let ancestors = cx.current().parent_iter(&cx.tree).collect::<HashSet<_>>();
58 let new_ancestors = id.parent_iter(&cx.tree).collect::<Vec<_>>();
59
60 fn insert_store<L>(
61 entity: Entity,
62 ancestors: &HashSet<Entity>,
63 stores: &mut HashMap<Entity, HashMap<StoreId, Box<dyn Store>>>,
64 model_data: ModelOrView,
65 lens: L,
66 id: Entity,
67 ) where
68 L: Lens<Target: Data>,
69 {
70 if !stores.contains_key(&entity) {
71 stores.insert(entity, HashMap::new());
72 }
73
74 if let Some(stores) = stores.get_mut(&entity) {
75 let key = lens.id();
76
77 if let Some(store) = stores.get_mut(&key) {
78 let observers = store.observers();
79
80 if ancestors.intersection(observers).next().is_none() {
81 store.add_observer(id);
82 }
83 } else {
84 let mut observers = HashSet::new();
85 observers.insert(id);
86
87 let model = model_data.downcast_ref::<L::Source>().unwrap();
88
89 let old = lens.view(model).map(|val| val.into_owned());
90
91 let store = Box::new(BasicStore { lens, old, observers });
92
93 stores.insert(key, store);
94 }
95 }
96 }
97
98 for entity in new_ancestors {
101 if let Some(view_handler) = cx.views.get(&entity) {
103 if view_handler.as_any_ref().is::<L::Source>() {
104 insert_store(
105 entity,
106 &ancestors,
107 &mut cx.stores,
108 ModelOrView::View(view_handler.as_ref()),
109 lens,
110 id,
111 );
112
113 break;
114 }
115 }
116
117 if let Some(models) = cx.models.get_mut(&entity) {
118 if let Some(model_data) = models.get(&TypeId::of::<L::Source>()) {
120 insert_store(
121 entity,
122 &ancestors,
123 &mut cx.stores,
124 ModelOrView::Model(model_data.as_ref()),
125 lens,
126 id,
127 );
128
129 break;
130 }
131 }
132 }
133
134 cx.bindings.insert(id, Box::new(binding));
135
136 cx.with_current(id, |cx| {
137 if let Some(mut binding) = cx.bindings.remove(&id) {
139 binding.update(cx);
140 cx.bindings.insert(id, binding);
141 }
142 });
143
144 let _: Handle<Self> =
145 Handle { current: id, entity: id, p: Default::default(), cx }.ignore();
146 }
147}
148
149pub(crate) trait BindingHandler {
150 fn update(&mut self, cx: &mut Context);
151 fn remove(&self, cx: &mut Context);
152 fn debug(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result;
153}
154
155impl<L: 'static + Lens> BindingHandler for Binding<L> {
156 fn update(&mut self, cx: &mut Context) {
157 cx.remove_children(cx.current());
158
159 MAP_MANAGER.with_borrow_mut(|manager| {
161 MAPS.with_borrow_mut(|maps| {
162 maps.retain(|id, (e, _)| {
163 if *e == self.entity {
164 manager.destroy(*id);
165 false
166 } else {
167 true
168 }
169 });
170 });
171 });
172
173 if let Some(builder) = &self.content {
174 CURRENT.with_borrow_mut(|f| *f = self.entity);
175 (builder)(cx, self.lens);
176 }
177 }
178
179 fn remove(&self, cx: &mut Context) {
180 for entity in self.entity.parent_iter(&cx.tree) {
181 let key = self.lens.id();
182
183 if let Some(stores) = cx.stores.get_mut(&entity) {
184 if let Some(store) = stores.get_mut(&key) {
185 let source = store.source();
186 if cx.views.get(&entity).filter(|view| view.id() == source).is_some()
187 || cx
188 .models
189 .get(&entity)
190 .filter(|models| models.contains_key(&source))
191 .is_some()
192 {
193 store.remove_observer(&self.entity);
194
195 if store.num_observers() == 0 {
196 stores.remove(&key);
197 }
198
199 break;
200 }
201 }
202 }
203 }
204 }
205
206 fn debug(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
207 self.lens.fmt(f)
208 }
209}
210
211impl std::fmt::Debug for dyn BindingHandler {
212 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213 self.debug(f)
214 }
215}