@@ -1,469 +0,0 @@
1−use crate::Listener;
2−use bumpalo::Bump;
3−use fxhash::FxHashMap;
4−use std::fmt;
5−
6−pub mod js {
7− cfg_if::cfg_if! {
8− if #[cfg(all(feature = "xxx-unstable-internal-use-only", not(target_arch = "wasm32")))] {
9− #[derive(Clone, Debug)]
10− pub struct ChangeList {}
11− impl ChangeList {
12− pub fn new(_container: &crate::Element) -> ChangeList {
13− ChangeList {}
14− }
15− pub fn unmount(&self) {}
16− pub fn add_change_list_range(&self, _start: usize, _len: usize) {}
17− pub fn init_events_trampoline(&self, _trampoline: &crate::EventsTrampoline) {}
18− }
19− } else {
20− use wasm_bindgen::prelude::*;
21−
22− #[wasm_bindgen(module = "/js/change-list.js")]
23− extern "C" {
24− #[derive(Clone, Debug)]
25− pub type ChangeList;
26−
27− #[wasm_bindgen(constructor)]
28− pub fn new(container: &web_sys::Element) -> ChangeList;
29−
30− #[wasm_bindgen(structural, method)]
31− pub fn unmount(this: &ChangeList);
32−
33− #[wasm_bindgen(structural, method, js_name = addChangeListRange)]
34− pub fn add_change_list_range(this: &ChangeList, start: usize, len: usize);
35−
36− #[wasm_bindgen(structural, method, js_name = applyChanges)]
37− pub fn apply_changes(this: &ChangeList, memory: JsValue);
38−
39− #[wasm_bindgen(structural, method, js_name = initEventsTrampoline)]
40− pub fn init_events_trampoline(
41− this: &ChangeList,
42− trampoline: &crate::EventsTrampoline,
43− );
44− }
45− }
46− }
47−}
48−
49−struct StringsCacheEntry {
50− key: u32,
51− used: bool,
52−}
53−
54−pub(crate) struct ChangeList {
55− bump: Bump,
56− strings_cache: FxHashMap<String, StringsCacheEntry>,
57− next_string_key: u32,
58− js: js::ChangeList,
59− events_trampoline: Option<crate::EventsTrampoline>,
60−}
61−
62−impl Drop for ChangeList {
63− fn drop(&mut self) {
64− debug!("Dropping ChangeList");
65− self.js.unmount();
66− }
67−}
68−
69−impl fmt::Debug for ChangeList {
70− fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71− f.debug_struct("ChangeList")
72− .field("bump", &self.bump)
73− .field("js", &self.js)
74− .field("events_trampoline", &"..")
75− .finish()
76− }
77−}
78−
79−impl ChangeList {
80− pub(crate) fn new(container: &crate::Element) -> ChangeList {
81− let bump = Bump::new();
82− let strings_cache = FxHashMap::default();
83− let js = js::ChangeList::new(container);
84− ChangeList {
85− bump,
86− strings_cache,
87− next_string_key: 0,
88− js,
89− events_trampoline: None,
90− }
91− }
92−
93− pub(crate) fn init_events_trampoline(&mut self, trampoline: crate::EventsTrampoline) {
94− debug_assert!(self.events_trampoline.is_none());
95− self.js.init_events_trampoline(&trampoline);
96− self.events_trampoline = Some(trampoline);
97− }
98−}
99−
100−cfg_if::cfg_if! {
101− if #[cfg(all(feature = "xxx-unstable-internal-use-only", not(target_arch = "wasm32")))] {
102− impl ChangeList {
103− pub(crate) fn apply_changes(&mut self) {
104− // Do nothing...
105− }
106− }
107− } else {
108− impl ChangeList {
109− pub(crate) fn apply_changes(&mut self) {
110− let js = &self.js;
111− unsafe {
112− self.bump.each_allocated_chunk(|ch| {
113− js.add_change_list_range(ch.as_ptr() as usize, ch.len());
114− });
115− }
116− js.apply_changes(wasm_bindgen::memory());
117− self.bump.reset();
118− }
119− }
120− }
121−}
122−
123−#[repr(u32)]
124−#[derive(Clone, Copy, Debug)]
125−enum ChangeDiscriminant {
126− /// Immediates: `(pointer, length)`
127− ///
128− /// Stack: `[... TextNode] -> [... TextNode]`
129− ///
130− /// ```text
131− /// stack.top().textContent = String(pointer, length)
132− /// ```
133− SetText = 0,
134−
135− /// Immediates: `()`
136− ///
137− /// Stack: `[... Node] -> [...]`
138− ///
139− /// ```text
140− /// node = stack.pop()
141− /// while (node.nextSibling) {
142− /// node.nextSibling.remove();
143− /// }
144− /// node.remove()
145− /// ```
146− RemoveSelfAndNextSiblings = 1,
147−
148− /// Immediates: `()`
149− ///
150− /// Stack: `[... Node Node] -> [... Node]`
151− ///
152− /// ```text
153− /// new = stack.pop()
154− /// old = stack.pop()
155− /// old.replaceWith(new)
156− /// stack.push(new)
157− /// ```
158− ReplaceWith = 2,
159−
160− /// Immediates: `(id1, id2)`
161− ///
162− /// Stack: `[... Node] -> [... Node]`
163− ///
164− /// ```text
165− /// stack.top().setAttribute(String(id1), String(id2))
166− /// ```
167− SetAttribute = 3,
168−
169− /// Immediates: (id)
170− ///
171− /// Stack: `[... Node] -> [... Node]`
172− ///
173− /// ```text
174− /// stack.top().removeAttribute(String(id))
175− /// ```
176− RemoveAttribute = 4,
177−
178− /// Immediates: `()`
179− ///
180− /// Stack: `[... Node] -> [... Node node]`
181− ///
182− /// ```text
183− /// stack.push(stack.top().firstChild)
184− /// ```
185− PushFirstChild = 5,
186−
187− /// Immediates: `()`
188− ///
189− /// Stack: `[... Node] -> [... Node]`
190− ///
191− /// ```text
192− /// stack.push(stack.pop().nextSibling)
193− /// ```
194− PopPushNextSibling = 6,
195−
196− /// Immediates: `()`
197− ///
198− /// Stack: `[... T] -> [...]`
199− ///
200− /// ```text
201− /// stack.pop()
202− /// ```
203− Pop = 7,
204−
205− /// Immediates: `()`
206− ///
207− /// Stack: `[... Node Node] -> [... Node]`
208− ///
209− /// ```text
210− /// child = stack.pop()
211− /// stack.top().appendChild(child)
212− /// ```
213− AppendChild = 8,
214−
215− /// Immediates: `(pointer, length)`
216− ///
217− /// Stack: `[...] -> [... Node]`
218− ///
219− /// ```text
220− /// stack.push(createTextNode(String(pointer, length)))
221− /// ```
222− CreateTextNode = 9,
223−
224− /// Immediates: `(id)`
225− ///
226− /// Stack: `[...] -> [... Node]`
227− ///
228− /// ```text
229− /// stack.push(createElement(String(id))
230− /// ```
231− CreateElement = 10,
232−
233− /// Immediates: `(id, A, B)`
234− ///
235− /// Stack: `[... Node] -> [... Node]`
236− ///
237− /// ```text
238− /// event = String(id)
239− /// callback = ProxyToRustCallback(A, B)
240− /// stack.top().addEventListener(event, callback)
241− /// ```
242− NewEventListener = 11,
243−
244− /// Immediates: `(id, A, B)`
245− ///
246− /// Stack: `[... Node] -> [... Node]`
247− ///
248− /// ```text
249− /// event = String(id)
250− /// new_callback = ProxyToRustCallback(A, B);
251− /// stack.top().updateEventlistener(new_callback)
252− /// ```
253− UpdateEventListener = 12,
254−
255− /// Immediates: `(id)`
256− ///
257− /// Stack: `[... Node] -> [... Node]`
258− ///
259− /// ```text
260− /// stack.top().removeEventListener(String(id));
261− /// ```
262− RemoveEventListener = 13,
263−
264− /// Immediates: `(pointer, length, id)`
265− ///
266− /// Stack: `[...] -> [...]`
267− ///
268− /// ```text
269− /// addString(String(pointer, length), id);
270− /// ```
271− AddString = 14,
272−
273− /// Immediates: `(id)`
274− ///
275− /// Stack: `[...] -> [...]`
276− ///
277− /// ```text
278− /// dropString(id);
279− /// ```
280− DropString = 15,
281−
282− /// Immediates: `(id1, id2)`
283− ///
284− /// Stack: `[...] -> [... Node]`
285− ///
286− /// ```text
287− /// stack.push(createElementNS(String(id1), String(id2))
288− /// ```
289− CreateElementNS = 16,
290−
291− /// Immediates: `(id1, id2, id3)`
292− ///
293− /// Stack: `[... Node] -> [... Node]`
294− ///
295− /// ```text
296− /// stack.top().setAttributeNS(String(id1), String(id2), String(id3))
297− /// ```
298− SetAttributeNS = 17,
299−}
300−
301−// Allocation utilities to ensure that we only allocation sequences of `u32`s
302−// into the change list's bump arena without any padding. This helps maintain
303−// the invariants required for `Bump::each_allocated_chunk`'s safety.
304−impl ChangeList {
305− // Allocate an opcode with zero immediates.
306− fn op0(&self, discriminant: ChangeDiscriminant) {
307− self.bump.alloc(discriminant as u32);
308− }
309−
310− // Allocate an opcode with one immediate.
311− fn op1(&self, discriminant: ChangeDiscriminant, a: u32) {
312− self.bump.alloc([discriminant as u32, a]);
313− }
314−
315− // Allocate an opcode with two immediates.
316− fn op2(&self, discriminant: ChangeDiscriminant, a: u32, b: u32) {
317− self.bump.alloc([discriminant as u32, a, b]);
318− }
319−
320− // Allocate an opcode with three immediates.
321− fn op3(&self, discriminant: ChangeDiscriminant, a: u32, b: u32, c: u32) {
322− self.bump.alloc([discriminant as u32, a, b, c]);
323− }
324−
325− // Note: no 4-immediate opcodes at this time.
326−}
327−
328−impl ChangeList {
329− fn ensure_string(&mut self, string: &str) -> u32 {
330− if let Some(entry) = self.strings_cache.get_mut(string) {
331− entry.used = true;
332− entry.key
333− } else {
334− let key = self.next_string_key;
335− self.next_string_key += 1;
336− let entry = StringsCacheEntry { key, used: true };
337− self.strings_cache.insert(string.to_string(), entry);
338− self.op3(
339− ChangeDiscriminant::AddString,
340− string.as_ptr() as u32,
341− string.len() as u32,
342− key,
343− );
344− key
345− }
346− }
347−
348− pub(crate) fn drop_unused_strings(&mut self) {
349− debug!("drop_unused_strings()");
350− let mut new_cache = FxHashMap::default();
351− for (key, val) in self.strings_cache.iter() {
352− if val.used {
353− new_cache.insert(
354− key.clone(),
355− StringsCacheEntry {
356− key: val.key,
357− used: false,
358− },
359− );
360− } else {
361− self.op1(ChangeDiscriminant::DropString, val.key);
362− }
363− }
364− self.strings_cache = new_cache;
365− }
366−
367− pub(crate) fn emit_set_text(&self, text: &str) {
368− debug!("emit_set_text({:?})", text);
369− self.op2(
370− ChangeDiscriminant::SetText,
371− text.as_ptr() as u32,
372− text.len() as u32,
373− );
374− }
375−
376− pub(crate) fn emit_remove_self_and_next_siblings(&self) {
377− debug!("emit_remove_self_and_next_siblings()");
378− self.op0(ChangeDiscriminant::RemoveSelfAndNextSiblings);
379− }
380−
381− pub(crate) fn emit_replace_with(&self) {
382− debug!("emit_replace_with()");
383− self.op0(ChangeDiscriminant::ReplaceWith);
384− }
385−
386− pub(crate) fn emit_set_attribute(&mut self, name: &str, value: &str) {
387− debug!("emit_set_attribute({:?}, {:?})", name, value);
388− let name_id = self.ensure_string(name);
389− let value_id = self.ensure_string(value);
390− self.op2(ChangeDiscriminant::SetAttribute, name_id, value_id);
391− }
392−
393− pub(crate) fn emit_set_attribute_ns(&mut self, name: &str, value: &str) {
394− debug!("emit_set_attribute_ns({:?}, {:?}", name, value);
395− let name_id = self.ensure_string(name);
396− let value_id = self.ensure_string(value);
397− self.op2(ChangeDiscriminant::SetAttributeNS, name_id, value_id);
398− }
399−
400− pub(crate) fn emit_remove_attribute(&mut self, name: &str) {
401− debug!("emit_remove_attribute({:?})", name);
402− let name_id = self.ensure_string(name);
403− self.op1(ChangeDiscriminant::RemoveAttribute, name_id);
404− }
405−
406− pub(crate) fn emit_push_first_child(&self) {
407− debug!("emit_push_first_child()");
408− self.op0(ChangeDiscriminant::PushFirstChild);
409− }
410−
411− pub(crate) fn emit_pop_push_next_sibling(&self) {
412− debug!("emit_pop_push_next_sibling()");
413− self.op0(ChangeDiscriminant::PopPushNextSibling);
414− }
415−
416− pub(crate) fn emit_pop(&self) {
417− debug!("emit_pop()");
418− self.op0(ChangeDiscriminant::Pop);
419− }
420−
421− pub(crate) fn emit_append_child(&self) {
422− debug!("emit_append_child()");
423− self.op0(ChangeDiscriminant::AppendChild);
424− }
425−
426− pub(crate) fn emit_create_text_node(&self, text: &str) {
427− debug!("emit_create_text_node({:?})", text);
428− self.op2(
429− ChangeDiscriminant::CreateTextNode,
430− text.as_ptr() as u32,
431− text.len() as u32,
432− );
433− }
434−
435− pub(crate) fn emit_create_element(&mut self, tag_name: &str) {
436− debug!("emit_create_element({:?})", tag_name);
437− let tag_name_id = self.ensure_string(tag_name);
438− self.op1(ChangeDiscriminant::CreateElement, tag_name_id);
439− }
440−
441− pub(crate) fn emit_create_element_ns(&mut self, tag_name: &str, ns: &str) {
442− debug!("emit_create_element_ns({:?}, {:?})", tag_name, ns);
443− let tag_name_id = self.ensure_string(tag_name);
444− let ns_id = self.ensure_string(ns);
445− self.op2(ChangeDiscriminant::CreateElementNS, tag_name_id, ns_id);
446− }
447−
448− pub(crate) fn emit_new_event_listener(&mut self, listener: &Listener) {
449− debug!("emit_new_event_listener({:?})", listener);
450− let (a, b) = listener.get_callback_parts();
451− debug_assert!(a != 0);
452− let event_id = self.ensure_string(listener.event);
453− self.op3(ChangeDiscriminant::NewEventListener, event_id, a, b);
454− }
455−
456− pub(crate) fn emit_update_event_listener(&mut self, listener: &Listener) {
457− debug!("emit_update_event_listener({:?})", listener);
458− let (a, b) = listener.get_callback_parts();
459− debug_assert!(a != 0);
460− let event_id = self.ensure_string(listener.event);
461− self.op3(ChangeDiscriminant::UpdateEventListener, event_id, a, b);
462− }
463−
464− pub(crate) fn emit_remove_event_listener(&mut self, event: &str) {
465− debug!("emit_remove_event_listener({:?})", event);
466− let event_id = self.ensure_string(event);
467− self.op1(ChangeDiscriminant::RemoveEventListener, event_id);
468− }
469−}