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