1use std::ops::{Deref, DerefMut};
4
5use blitz_dom::NodeId;
6use blitz_traits::events::{DomEvent, EventState};
7use url::Url;
8use web_time::{Duration, Instant};
9
10pub use crate::job_budget::{JobBudget, JobSlice};
11use crate::runtime::BoaScriptEngine;
12use crate::runtime::{DiagnosticBatch, DiagnosticEntry};
13
14pub trait ScriptEngine {
19 type JobScope;
20 fn eval(&mut self, code: &str, description: &str);
21 fn eval_at(&mut self, code: &str, url: Option<&Url>, description: &str);
22 fn eval_internal(&mut self, code: &str, description: &str);
23 fn eval_module(&mut self, code: &str, url: Option<&Url>, description: &str);
24 fn eval_json(&mut self, code: &str, description: &str) -> Result<serde_json::Value, String>;
25 fn set_import_map(&self, json: &str, base_url: Option<&Url>);
26 fn poll_module_evaluations(&mut self);
27 fn has_pending_module_evaluations(&self) -> bool;
28 fn has_pending_module_loads(&self) -> bool;
29 fn begin_job_slice(&self) -> Self::JobScope;
30 fn job_budget(&self) -> Duration;
31 fn set_job_budget(&self, duration: Duration);
32 fn pending_task_count(&self) -> u64;
33 fn job_slice_exhausted(&self) -> bool;
34 fn jobs_remain(&self) -> bool;
35 fn run_jobs(&mut self, description: &str);
36 fn run_jobs_with_progress(&mut self, description: &str) -> bool;
37 fn next_timer_deadline(&self) -> Option<Instant>;
38 fn run_due_timers(&mut self, profiling: bool) -> bool;
39 fn dispatch_dom_event(
40 &mut self,
41 chain: &[NodeId],
42 event: &DomEvent,
43 event_state: &mut EventState,
44 profiling: bool,
45 ) -> bool;
46 fn dispatch_document_event(&mut self, name: &str) -> bool;
47 fn dispatch_node_event(&mut self, node_id: NodeId, name: &str) -> bool;
48 fn dispatch_window_event(&mut self, name: &str) -> bool;
49 fn set_document_ready_state(&mut self, next: &'static str) -> bool;
50 fn sweep_detached_nodes(&mut self);
51 fn poll_domc(&mut self) -> bool;
52 fn console_entries_after(&self, sequence: u64) -> Vec<DiagnosticEntry>;
53 fn runtime_errors_after(&self, sequence: u64) -> Vec<DiagnosticEntry>;
54 fn diagnostic_batch(
55 &self,
56 console_after: u64,
57 errors_after: u64,
58 limit: usize,
59 ) -> DiagnosticBatch;
60}
61
62pub struct Engine<E: ScriptEngine> {
68 backend: E,
69}
70
71impl<E: ScriptEngine> Engine<E> {
72 pub fn new(backend: E) -> Self {
73 Self { backend }
74 }
75
76 pub fn backend(&self) -> &E {
77 &self.backend
78 }
79
80 pub fn backend_mut(&mut self) -> &mut E {
81 &mut self.backend
82 }
83
84 pub fn eval(&mut self, code: &str, description: &str) {
85 self.backend.eval(code, description)
86 }
87
88 pub fn eval_at(&mut self, code: &str, url: Option<&Url>, description: &str) {
89 self.backend.eval_at(code, url, description)
90 }
91
92 pub fn eval_internal(&mut self, code: &str, description: &str) {
93 self.backend.eval_internal(code, description)
94 }
95
96 pub fn eval_module(&mut self, code: &str, url: Option<&Url>, description: &str) {
97 self.backend.eval_module(code, url, description)
98 }
99
100 pub fn eval_json(
101 &mut self,
102 code: &str,
103 description: &str,
104 ) -> Result<serde_json::Value, String> {
105 self.backend.eval_json(code, description)
106 }
107
108 pub fn set_import_map(&self, json: &str, base_url: Option<&Url>) {
109 self.backend.set_import_map(json, base_url)
110 }
111
112 pub fn poll_module_evaluations(&mut self) {
113 self.backend.poll_module_evaluations()
114 }
115
116 pub fn has_pending_module_evaluations(&self) -> bool {
117 self.backend.has_pending_module_evaluations()
118 }
119
120 pub fn has_pending_module_loads(&self) -> bool {
121 self.backend.has_pending_module_loads()
122 }
123
124 pub fn begin_job_slice(&self) -> E::JobScope {
125 self.backend.begin_job_slice()
126 }
127
128 pub fn job_budget(&self) -> Duration {
129 self.backend.job_budget()
130 }
131
132 pub fn set_job_budget(&self, duration: Duration) {
133 self.backend.set_job_budget(duration)
134 }
135
136 pub fn pending_task_count(&self) -> u64 {
137 self.backend.pending_task_count()
138 }
139
140 pub fn job_slice_exhausted(&self) -> bool {
141 self.backend.job_slice_exhausted()
142 }
143
144 pub fn jobs_remain(&self) -> bool {
145 self.backend.jobs_remain()
146 }
147
148 pub fn run_jobs(&mut self, description: &str) {
149 self.backend.run_jobs(description)
150 }
151
152 pub fn run_jobs_with_progress(&mut self, description: &str) -> bool {
153 self.backend.run_jobs_with_progress(description)
154 }
155
156 pub fn next_timer_deadline(&self) -> Option<Instant> {
157 self.backend.next_timer_deadline()
158 }
159
160 pub fn run_due_timers(&mut self, profiling: bool) -> bool {
161 self.backend.run_due_timers(profiling)
162 }
163
164 pub fn dispatch_dom_event(
165 &mut self,
166 chain: &[NodeId],
167 event: &DomEvent,
168 event_state: &mut EventState,
169 profiling: bool,
170 ) -> bool {
171 self.backend
172 .dispatch_dom_event(chain, event, event_state, profiling)
173 }
174
175 pub fn dispatch_document_event(&mut self, name: &str) -> bool {
176 self.backend.dispatch_document_event(name)
177 }
178
179 pub fn dispatch_node_event(&mut self, node_id: NodeId, name: &str) -> bool {
180 self.backend.dispatch_node_event(node_id, name)
181 }
182
183 pub fn dispatch_window_event(&mut self, name: &str) -> bool {
184 self.backend.dispatch_window_event(name)
185 }
186
187 pub fn set_document_ready_state(&mut self, next: &'static str) -> bool {
188 self.backend.set_document_ready_state(next)
189 }
190
191 pub fn sweep_detached_nodes(&mut self) {
192 self.backend.sweep_detached_nodes()
193 }
194
195 pub fn poll_domc(&mut self) -> bool {
196 self.backend.poll_domc()
197 }
198
199 pub fn console_entries_after(&self, sequence: u64) -> Vec<DiagnosticEntry> {
200 self.backend.console_entries_after(sequence)
201 }
202
203 pub fn runtime_errors_after(&self, sequence: u64) -> Vec<DiagnosticEntry> {
204 self.backend.runtime_errors_after(sequence)
205 }
206
207 pub fn diagnostic_batch(
208 &self,
209 console_after: u64,
210 errors_after: u64,
211 limit: usize,
212 ) -> DiagnosticBatch {
213 self.backend
214 .diagnostic_batch(console_after, errors_after, limit)
215 }
216}
217
218impl<E: ScriptEngine> Deref for Engine<E> {
219 type Target = E;
220
221 fn deref(&self) -> &E {
222 &self.backend
223 }
224}
225
226impl<E: ScriptEngine> DerefMut for Engine<E> {
227 fn deref_mut(&mut self) -> &mut E {
228 &mut self.backend
229 }
230}
231
232impl ScriptEngine for BoaScriptEngine {
233 type JobScope = JobSlice;
234
235 fn eval(&mut self, code: &str, description: &str) {
236 BoaScriptEngine::eval(self, code, description)
237 }
238
239 fn eval_at(&mut self, code: &str, url: Option<&Url>, description: &str) {
240 BoaScriptEngine::eval_at(self, code, url, description)
241 }
242
243 fn eval_internal(&mut self, code: &str, description: &str) {
244 BoaScriptEngine::eval_internal(self, code, description)
245 }
246
247 fn eval_module(&mut self, code: &str, url: Option<&Url>, description: &str) {
248 BoaScriptEngine::eval_module(self, code, url, description)
249 }
250
251 fn eval_json(&mut self, code: &str, description: &str) -> Result<serde_json::Value, String> {
252 BoaScriptEngine::eval_json(self, code, description)
253 }
254
255 fn set_import_map(&self, json: &str, base_url: Option<&Url>) {
256 BoaScriptEngine::set_import_map(self, json, base_url)
257 }
258
259 fn poll_module_evaluations(&mut self) {
260 BoaScriptEngine::poll_module_evaluations(self)
261 }
262
263 fn has_pending_module_evaluations(&self) -> bool {
264 BoaScriptEngine::has_pending_module_evaluations(self)
265 }
266
267 fn has_pending_module_loads(&self) -> bool {
268 BoaScriptEngine::has_pending_module_loads(self)
269 }
270
271 fn begin_job_slice(&self) -> Self::JobScope {
272 BoaScriptEngine::begin_job_slice(self)
273 }
274
275 fn job_budget(&self) -> Duration {
276 BoaScriptEngine::job_budget(self)
277 }
278
279 fn set_job_budget(&self, duration: Duration) {
280 BoaScriptEngine::set_job_budget(self, duration)
281 }
282
283 fn pending_task_count(&self) -> u64 {
284 BoaScriptEngine::pending_task_count(self)
285 }
286
287 fn job_slice_exhausted(&self) -> bool {
288 BoaScriptEngine::job_slice_exhausted(self)
289 }
290
291 fn jobs_remain(&self) -> bool {
292 BoaScriptEngine::jobs_remain(self)
293 }
294
295 fn run_jobs(&mut self, description: &str) {
296 BoaScriptEngine::run_jobs(self, description)
297 }
298
299 fn run_jobs_with_progress(&mut self, description: &str) -> bool {
300 BoaScriptEngine::run_jobs_with_progress(self, description)
301 }
302
303 fn next_timer_deadline(&self) -> Option<Instant> {
304 BoaScriptEngine::next_timer_deadline(self)
305 }
306
307 fn run_due_timers(&mut self, profiling: bool) -> bool {
308 BoaScriptEngine::run_due_timers(self, profiling)
309 }
310
311 fn dispatch_dom_event(
312 &mut self,
313 chain: &[NodeId],
314 event: &DomEvent,
315 event_state: &mut EventState,
316 profiling: bool,
317 ) -> bool {
318 BoaScriptEngine::dispatch_dom_event(self, chain, event, event_state, profiling)
319 }
320
321 fn dispatch_document_event(&mut self, name: &str) -> bool {
322 BoaScriptEngine::dispatch_document_event(self, name)
323 }
324
325 fn dispatch_node_event(&mut self, node_id: NodeId, name: &str) -> bool {
326 BoaScriptEngine::dispatch_node_event(self, node_id, name)
327 }
328
329 fn dispatch_window_event(&mut self, name: &str) -> bool {
330 BoaScriptEngine::dispatch_window_event(self, name)
331 }
332
333 fn set_document_ready_state(&mut self, next: &'static str) -> bool {
334 BoaScriptEngine::set_document_ready_state(self, next)
335 }
336
337 fn sweep_detached_nodes(&mut self) {
338 BoaScriptEngine::sweep_detached_nodes(self)
339 }
340
341 fn poll_domc(&mut self) -> bool {
342 BoaScriptEngine::poll_domc(self)
343 }
344
345 fn console_entries_after(&self, sequence: u64) -> Vec<DiagnosticEntry> {
346 BoaScriptEngine::console_entries_after(self, sequence)
347 }
348
349 fn runtime_errors_after(&self, sequence: u64) -> Vec<DiagnosticEntry> {
350 BoaScriptEngine::runtime_errors_after(self, sequence)
351 }
352
353 fn diagnostic_batch(
354 &self,
355 console_after: u64,
356 errors_after: u64,
357 limit: usize,
358 ) -> DiagnosticBatch {
359 BoaScriptEngine::diagnostic_batch(self, console_after, errors_after, limit)
360 }
361}