1use std::cell::RefCell;
2use std::future::Future;
3use std::iter::IntoIterator;
4use std::rc::Rc;
5
6use discard::{Discard, DiscardOnDrop};
7use futures_signals::signal::{Signal, SignalExt};
8use futures_signals::signal_vec::{SignalVec, SignalVecExt, VecDiff};
9use futures_signals::{cancelable_future, CancelableFutureHandle};
10use futures_util::future::ready;
11use wasm_bindgen::UnwrapThrowExt;
12use wasm_bindgen_futures::spawn_local;
13use web_sys::Node;
14
15use crate::bindings;
16use crate::callbacks::Callbacks;
17use crate::dom::Dom;
18
19#[inline]
20pub(crate) fn spawn_future<F>(future: F) -> DiscardOnDrop<CancelableFutureHandle>
21where
22 F: Future<Output = ()> + 'static,
23{
24 let (handle, future) = cancelable_future(future, || ());
26
27 spawn_local(future);
28
29 handle
30}
31
32#[inline]
33pub(crate) fn for_each<A, B>(signal: A, mut callback: B) -> CancelableFutureHandle
34where
35 A: Signal + 'static,
36 B: FnMut(A::Item) + 'static,
37{
38 DiscardOnDrop::leak(spawn_future(signal.for_each(move |value| {
39 callback(value);
40 ready(())
41 })))
42}
43
44#[inline]
45fn for_each_vec<A, B>(signal: A, mut callback: B) -> CancelableFutureHandle
46where
47 A: SignalVec + 'static,
48 B: FnMut(VecDiff<A::Item>) + 'static,
49{
50 DiscardOnDrop::leak(spawn_future(signal.for_each(move |value| {
51 callback(value);
52 ready(())
53 })))
54}
55
56pub(crate) fn insert_children_one(element: &Node, callbacks: &mut Callbacks, dom: &mut Dom) {
57 callbacks
59 .after_insert
60 .append(&mut dom.callbacks.after_insert);
61 callbacks
62 .after_remove
63 .append(&mut dom.callbacks.after_remove);
64
65 bindings::append_child(element, &dom.element);
66}
67
68#[inline]
69pub(crate) fn insert_children_iter<A: std::borrow::BorrowMut<Dom>, B: IntoIterator<Item = A>>(
70 element: &Node,
71 callbacks: &mut Callbacks,
72 value: B,
73) {
74 for mut dom in value {
75 let dom = std::borrow::BorrowMut::borrow_mut(&mut dom);
76 insert_children_one(element, callbacks, dom);
77 }
78}
79
80fn after_insert(is_inserted: bool, callbacks: &mut Callbacks) {
81 callbacks.leak();
82
83 if is_inserted {
84 callbacks.trigger_after_insert();
85 }
86}
87
88#[inline]
89pub(crate) fn insert_child_signal<A>(element: Node, callbacks: &mut Callbacks, signal: A)
90where
91 A: Signal<Item = Option<Dom>> + 'static,
92{
93 struct State {
94 is_inserted: bool,
95 child: Option<Dom>,
96 }
97
98 impl State {
99 fn new() -> Rc<RefCell<Self>> {
100 Rc::new(RefCell::new(State {
101 is_inserted: false,
102 child: None,
103 }))
104 }
105
106 fn after_insert(state: Rc<RefCell<Self>>, callbacks: &mut Callbacks) {
107 callbacks.after_insert(move |_| {
108 let mut state = state.borrow_mut();
109
110 if !state.is_inserted {
111 state.is_inserted = true;
112
113 if let Some(ref mut child) = state.child {
114 child.callbacks.trigger_after_insert();
115 }
116 }
117 });
118 }
119
120 fn after_remove(&mut self, element: &Node, marker: &Node, child: Option<Dom>) {
122 if let Some(old_child) = self.child.take() {
123 bindings::remove_child(&element, &old_child.element);
124
125 old_child.callbacks.discard();
126 }
127
128 self.child = child;
129
130 if let Some(new_child) = &mut self.child {
131 bindings::insert_child_before(element, &new_child.element, marker);
132
133 after_insert(self.is_inserted, &mut new_child.callbacks);
134 }
135 }
136
137 fn on_remove(&mut self) {
138 if let Some(old_child) = self.child.take() {
139 old_child.callbacks.discard();
140 }
141 }
142 }
143
144 struct OnRemove {
145 state: Rc<RefCell<State>>,
146 signal: CancelableFutureHandle,
147 }
148
149 impl Discard for OnRemove {
150 #[inline]
151 fn discard(self) {
152 self.signal.discard();
153 self.state.borrow_mut().on_remove();
154 }
155 }
156
157 let marker = bindings::create_empty_node();
159
160 bindings::append_child(&element, &marker);
161
162 let state = State::new();
163
164 State::after_insert(state.clone(), callbacks);
165
166 callbacks.after_remove(OnRemove {
167 state: state.clone(),
168 signal: for_each(signal, move |child| {
169 let mut state = state.borrow_mut();
170 state.after_remove(&element, &marker, child);
171 }),
172 });
173}
174
175#[inline]
176pub(crate) fn insert_children_signal_vec<A>(element: Node, callbacks: &mut Callbacks, signal: A)
177where
178 A: SignalVec<Item = Dom> + 'static,
179{
180 struct State {
181 element: Node,
182 marker: Node,
183 is_inserted: bool,
184 children: Vec<Dom>,
185 }
186
187 impl State {
188 fn new(element: Node, marker: Node) -> Rc<RefCell<Self>> {
189 Rc::new(RefCell::new(State {
190 element,
191 marker,
192 is_inserted: false,
193 children: vec![],
194 }))
195 }
196
197 fn after_insert(state: Rc<RefCell<Self>>, callbacks: &mut Callbacks) {
198 callbacks.after_insert(move |_| {
199 let mut state = state.borrow_mut();
200
201 if !state.is_inserted {
202 state.is_inserted = true;
203
204 for dom in state.children.iter_mut() {
205 dom.callbacks.trigger_after_insert();
206 }
207 }
208 });
209 }
210
211 fn clear(&mut self) {
212 for dom in self.children.drain(..) {
213 bindings::remove_child(&self.element, &dom.element);
214 dom.callbacks.discard();
215 }
216 }
217
218 fn on_remove(&mut self) {
219 for dom in self.children.drain(..) {
220 dom.callbacks.discard();
221 }
222 }
223
224 fn insert_at(&self, new_index: usize, child: &Node) {
225 if let Some(dom) = self.children.get(new_index) {
226 bindings::insert_child_before(&self.element, child, &dom.element);
227 } else {
228 bindings::insert_child_before(&self.element, child, &self.marker);
229 }
230 }
231
232 fn process_change(&mut self, change: VecDiff<Dom>) {
234 match change {
235 VecDiff::Replace { values } => {
236 self.clear();
237
238 self.children = values;
239
240 let is_inserted = self.is_inserted;
241
242 for dom in self.children.iter_mut() {
244 bindings::insert_child_before(&self.element, &dom.element, &self.marker);
245
246 after_insert(is_inserted, &mut dom.callbacks);
247 }
248 }
249
250 VecDiff::InsertAt { index, mut value } => {
251 self.insert_at(index, &value.element);
252
253 after_insert(self.is_inserted, &mut value.callbacks);
254
255 self.children.insert(index, value);
257 }
258
259 VecDiff::Push { mut value } => {
260 bindings::insert_child_before(&self.element, &value.element, &self.marker);
261
262 after_insert(self.is_inserted, &mut value.callbacks);
263
264 self.children.push(value);
266 }
267
268 VecDiff::UpdateAt { index, mut value } => {
269 let dom = &mut self.children[index];
270
271 bindings::replace_child(&self.element, &value.element, &dom.element);
272
273 after_insert(self.is_inserted, &mut value.callbacks);
274
275 ::std::mem::swap(dom, &mut value);
278
279 value.callbacks.discard();
280 }
281
282 VecDiff::Move {
283 old_index,
284 new_index,
285 } => {
286 let value = self.children.remove(old_index);
287
288 self.insert_at(new_index, &value.element);
289
290 self.children.insert(new_index, value);
291 }
292
293 VecDiff::RemoveAt { index } => {
294 let dom = self.children.remove(index);
295
296 bindings::remove_child(&self.element, &dom.element);
297
298 dom.callbacks.discard();
299 }
300
301 VecDiff::Pop {} => {
302 let dom = self.children.pop().unwrap_throw();
303
304 bindings::remove_child(&self.element, &dom.element);
305
306 dom.callbacks.discard();
307 }
308
309 VecDiff::Clear {} => {
310 self.clear();
311 }
312 }
313 }
314 }
315
316 struct OnRemove {
317 state: Rc<RefCell<State>>,
318 signal: CancelableFutureHandle,
319 }
320
321 impl Discard for OnRemove {
322 #[inline]
323 fn discard(self) {
324 self.signal.discard();
325 self.state.borrow_mut().on_remove();
326 }
327 }
328
329 let marker = bindings::create_empty_node();
331
332 bindings::append_child(&element, &marker);
333
334 let state = State::new(element, marker);
335
336 State::after_insert(state.clone(), callbacks);
337
338 callbacks.after_remove(OnRemove {
339 state: state.clone(),
340 signal: for_each_vec(signal, move |change| {
341 let mut state = state.borrow_mut();
342 state.process_change(change);
343 }),
344 });
345}