char/avril

(wip) why'd you have to go and make things so complicaaaaated?

git clone https://git.t4t.associates/char/avril

Charlotte Somsnapshot: capture and restore extension layouts in one artifactd71572b

main
2.4 KiB83 linesraw
1use std::cell::RefCell;
2use std::collections::VecDeque;
3use std::rc::Rc;
4
5struct Task {
6    run: v8::Global<v8::Function>,
7    finish: v8::Global<v8::Function>,
8}
9
10type Tasks = Rc<RefCell<VecDeque<Task>>>;
11
12pub(crate) fn clear(isolate: &mut v8::Isolate) {
13    isolate.remove_slot::<Tasks>();
14}
15
16pub(crate) fn init(isolate: &mut v8::Isolate) {
17    isolate.set_slot::<Tasks>(Rc::new(RefCell::new(VecDeque::new())));
18}
19
20pub(crate) fn enqueue<'s>(
21    scope: &mut v8::PinScope<'s, '_>,
22    args: v8::FunctionCallbackArguments<'s>,
23    _result: v8::ReturnValue,
24) {
25    let (Ok(run), Ok(finish)) = (
26        v8::Local::<v8::Function>::try_from(args.get(0)),
27        v8::Local::<v8::Function>::try_from(args.get(1)),
28    ) else {
29        let message = v8::String::new(scope, "Tasks require run and finish callbacks").unwrap();
30        let error = v8::Exception::type_error(scope, message);
31        scope.throw_exception(error);
32        return;
33    };
34    let task = Task {
35        run: v8::Global::new(scope, run),
36        finish: v8::Global::new(scope, finish),
37    };
38    scope
39        .get_slot::<Tasks>()
40        .unwrap()
41        .borrow_mut()
42        .push_back(task);
43    if let Some(waker) = scope.get_slot::<std::task::Waker>() {
44        waker.wake_by_ref();
45    }
46}
47
48pub(crate) fn has_pending(isolate: &v8::Isolate) -> bool {
49    !isolate.get_slot::<Tasks>().unwrap().borrow().is_empty()
50}
51
52pub(crate) fn run_next(scope: &mut v8::PinScope) -> Option<bool> {
53    let task = scope.get_slot::<Tasks>().unwrap().borrow_mut().pop_front();
54    let Some(task) = task else {
55        return Some(false);
56    };
57    v8::tc_scope!(let scope, scope);
58    let receiver = v8::undefined(scope).into();
59    let run = v8::Local::new(scope, task.run);
60    let error = if run.call(scope, receiver, &[]).is_none() {
61        let error = v8::Global::new(scope, scope.exception()?);
62        scope.reset();
63        Some(error)
64    } else {
65        None
66    };
67    // Post-callback steps such as repeating a timer follow its full microtask checkpoint.
68    crate::op::checkpoint(scope);
69    let finish = v8::Local::new(scope, task.finish);
70    let finished = finish.call(scope, receiver, &[]).is_some();
71    if let Some(error) = error {
72        scope.reset();
73        let error = v8::Local::new(scope, error);
74        scope.throw_exception(error);
75        scope.rethrow();
76        return None;
77    }
78    if !finished {
79        scope.rethrow();
80        return None;
81    }
82    Some(true)
83}