char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
d71572b
main
1use std:: cell:: RefCell ; 2use std:: future:: Future ; 3use std:: pin:: Pin ; 4use std:: rc:: Rc ; 5use std:: task::{ Context , Poll }; 6 7use futures:: FutureExt ; 8use futures:: future:: LocalBoxFuture ; 9use futures:: stream::{ FuturesUnordered , StreamExt }; 10use serde::{ Serialize , de:: DeserializeOwned }; 11use v8:: MapFnTo ; 12 13trait OpTask : Future < Output =()> { 14fn complete ( self : Pin < & mut Self >, scope : & mut v8:: PinScope ); 15} 16 17// Keep the concrete result in the future's allocation until V8 can serialize it. 18pin_project_lite:: pin_project!{ 19struct OpFuture < F : Future > { 20# [ pin ] 21future : futures:: future:: MaybeDone < F >, 22resolver : v8:: Global < v8:: PromiseResolver >, 23} 24} 25 26impl < F : Future > Future for OpFuture < F > { 27type Output =(); 28 29fn poll ( self : Pin < & mut Self >, cx : & mut Context < ' _ >) ->Poll <()> { 30self . project (). future . poll ( cx) 31} 32} 33 34impl < F , R , E > OpTask for OpFuture < F > 35where 36F : Future < Output =Result < R , E >>, 37R : Serialize , 38E : std:: error:: Error , 39{ 40fn complete ( self : Pin < & mut Self >, scope : & mut v8:: PinScope ) { 41let this =self . project (); 42let result = this 43. future 44. take_output () 45. expect ( "op completed before its future was ready" ) 46. map_err ( |error|OpError :: Error ( error. to_string ())) 47. and_then ( |value|{ 48 serde_v8:: to_v8 ( scope, value). map_err ( |error|OpError :: Error ( error. to_string ())) 49}); 50let resolver = v8:: Local :: new ( scope, &* this. resolver ); 51match result{ 52Ok ( value) =>{ 53 resolver. resolve ( scope, value); 54} 55Err ( error) =>{ 56let error = error. exception ( scope); 57 resolver. reject ( scope, error); 58} 59} 60} 61} 62 63struct OpCompletion { 64future : Pin < Box < dyn OpTask >>, 65referenced : bool , 66} 67 68enum Completion { 69Op ( OpCompletion ), 70Import ( crate :: modules:: ImportPreparation ), 71} 72 73enum Pending { 74Op ( Option < OpCompletion >), 75Import ( LocalBoxFuture < ' static , crate :: modules:: ImportPreparation >), 76} 77 78impl Future for Pending { 79type Output =Completion ; 80 81fn poll ( self : Pin < & mut Self >, cx : & mut Context < ' _ >) ->Poll < Completion > { 82match self . get_mut () { 83Self :: Op ( completion) =>{ 84 std:: task:: ready!( completion. as_mut (). unwrap (). future . as_mut (). poll ( cx)); 85Poll :: Ready ( Completion :: Op ( completion. take (). unwrap ())) 86} 87Self :: Import ( future) => future. as_mut (). poll ( cx). map ( Completion :: Import ), 88} 89} 90} 91 92struct PendingOps { 93futures : FuturesUnordered < Pending >, 94referenced : usize , 95} 96enum RejectionPromise { 97Pending ( v8:: Global < v8:: Promise >), 98Reported ( v8:: Weak < v8:: Promise >), 99} 100struct Rejection { 101promise : RejectionPromise , 102reason : Option < v8:: Global < v8:: Value >>, 103} 104type Rejections =Rc < RefCell < Vec < Rejection >>>; 105type HandledRejections =Rc < RefCell < Vec <( v8:: Global < v8:: Promise >, v8:: Global < v8:: Value >)>>>; 106 107extern "C" fn promise_rejected ( message : v8:: PromiseRejectMessage ) { 108// SAFETY: V8 invokes this callback with a promise belonging to the active isolate. 109 v8:: callback_scope!( unsafe scope, & message); 110let rejections = scope. get_slot ::< Rejections >(). unwrap (). clone (); 111match message. get_event () { 112 v8:: PromiseRejectEvent :: PromiseRejectWithNoHandler =>{ 113let promise = message. get_promise (); 114let mut rejections = rejections. borrow_mut (); 115if !rejections. iter (). any ( |rejection|match & rejection. promise { 116RejectionPromise :: Pending ( promise_global) =>{ 117 v8:: Local :: new ( scope, promise_global) == promise 118} 119RejectionPromise :: Reported ( weak) =>{ 120 weak. to_local ( scope). is_some_and ( |value| value == promise) 121} 122}) { 123 rejections. push ( Rejection { 124promise : RejectionPromise :: Pending ( v8:: Global :: new ( scope, promise)), 125reason : Some ( v8:: Global :: new ( scope, message. get_value (). unwrap ())), 126}); 127} 128} 129 v8:: PromiseRejectEvent :: PromiseHandlerAddedAfterReject =>{ 130let promise = message. get_promise (); 131let handled ={ 132let mut rejections = rejections. borrow_mut (); 133 rejections 134. iter () 135. position ( |rejection|match & rejection. promise { 136RejectionPromise :: Pending ( promise_global) =>{ 137 v8:: Local :: new ( scope, promise_global) == promise 138} 139RejectionPromise :: Reported ( weak) =>{ 140 weak. to_local ( scope). is_some_and ( |value| value == promise) 141} 142}) 143. map ( |index| rejections. remove ( index)) 144}; 145if let Some ( rejection) = handled 146 &&matches! ( rejection. promise , RejectionPromise :: Reported ( _)) 147{ 148let reason = promise. result ( scope); 149let handled = scope. get_slot ::< HandledRejections >(). unwrap (). clone (); 150 handled. borrow_mut (). push (( 151 v8:: Global :: new ( scope, promise), 152 v8:: Global :: new ( scope, reason), 153)); 154} 155} 156 _ =>{} 157} 158} 159 160pub ( crate ) fn mark_promise_handled < ' s >( 161scope : & mut v8:: PinScope < ' s , ' _ >, 162args : v8:: FunctionCallbackArguments < ' s >, 163_result : v8:: ReturnValue , 164) { 165let Ok ( promise) = v8:: Local ::< v8:: Promise >:: try_from ( args. get ( 0 )) else { 166let message = v8:: String :: new ( scope, "Expected a promise" ). unwrap (); 167let error = v8:: Exception :: type_error ( scope, message); 168 scope. throw_exception ( error); 169return ; 170}; 171// MarkAsHandled also notifies our rejection tracker for already-rejected promises. 172 promise. mark_as_handled (); 173} 174 175/// Reads a promise's state for inspection: undefined for non-promises, 176/// otherwise `[state, result]`, where state 0 is pending, 1 fulfilled and 177/// 2 rejected. JavaScript cannot observe this synchronously. 178pub ( crate ) fn promise_state < ' s >( 179scope : & mut v8:: PinScope < ' s , ' _ >, 180args : v8:: FunctionCallbackArguments < ' s >, 181mut result : v8:: ReturnValue , 182) { 183let Ok ( promise) = v8:: Local ::< v8:: Promise >:: try_from ( args. get ( 0 )) else { 184return ; 185}; 186let ( state, value) =match promise. state () { 187 v8:: PromiseState :: Pending =>( 0 , v8:: undefined ( scope). into ()), 188 v8:: PromiseState :: Fulfilled =>( 1 , promise. result ( scope)), 189 v8:: PromiseState :: Rejected =>( 2 , promise. result ( scope)), 190}; 191let state = v8:: Integer :: new ( scope, state). into (); 192 result. set ( v8:: Array :: new_with_elements ( scope, & [ state, value]). into ()); 193} 194 195pub ( crate ) fn perform_promise_then < ' s >( 196scope : & mut v8:: PinScope < ' s , ' _ >, 197args : v8:: FunctionCallbackArguments < ' s >, 198mut result : v8:: ReturnValue , 199) { 200let ( Ok ( promise), Ok ( fulfilled), Ok ( rejected)) =( 201 v8:: Local ::< v8:: Promise >:: try_from ( args. get ( 0 )), 202 v8:: Local ::< v8:: Function >:: try_from ( args. get ( 1 )), 203 v8:: Local ::< v8:: Function >:: try_from ( args. get ( 2 )), 204) else { 205let message = v8:: String :: new ( scope, "Expected a promise and two handlers" ). unwrap (); 206let error = v8:: Exception :: type_error ( scope, message); 207 scope. throw_exception ( error); 208return ; 209}; 210// V8's API uses PerformPromiseThen, not the species-sensitive JS builtin. 211if let Some ( promise) = promise. then2 ( scope, fulfilled, rejected) { 212 result. set ( promise. into ()); 213} 214} 215 216type Callback =dyn for < ' s , ' i > Fn ( 217& mut v8:: PinScope < ' s , ' i >, 218 v8:: FunctionCallbackArguments < ' s >, 219) ->Option < v8:: Local < ' s , v8:: Value >>; 220 221pub struct Op { 222pub name : &' static str , 223callback : Box < Callback >, 224} 225 226# [ derive ( Clone )] 227pub ( crate ) struct RegisteredOps { 228ops : Rc <[ Op ]>, 229} 230 231impl RegisteredOps { 232pub ( crate ) fn new ( mut ops : Vec < Op >) ->Result < Self , crate :: Error > { 233// Snapshot indices depend on names, not extension order or native addresses. 234// Restoring requires the same op names; adding or removing an op invalidates the snapshot. 235 ops. sort_unstable_by_key ( |op| op. name ); 236for pairin ops. windows ( 2 ) { 237if pair[ 0 ]. name == pair[ 1 ]. name { 238return Err ( crate :: Error :: DuplicateOp ( pair[ 0 ]. name )); 239} 240} 241Ok ( Self { ops : ops. into () }) 242} 243 244pub ( crate ) fn external_references () ->Vec < v8:: ExternalReference > { 245vec! [ v8:: ExternalReference { function : dispatch. map_fn_to () }] 246} 247 248pub ( crate ) fn object < ' s >( 249& self , 250scope : & mut v8:: PinScope < ' s , ' _ >, 251) ->Option < v8:: Local < ' s , v8:: Object >> { 252let registry = v8:: Object :: new ( scope); 253 registry. set_prototype ( scope, v8:: null ( scope). into ()) ?; 254for ( index, op) in self . ops . iter (). enumerate () { 255let key = v8:: String :: new ( scope, op. name ) ?; 256let data = 257 v8:: Integer :: new_from_unsigned ( scope, index. try_into (). expect ( "Too many ops" )); 258let function = v8:: Function :: builder ( dispatch) 259. constructor_behavior ( v8:: ConstructorBehavior :: Throw ) 260. data ( data. into ()) 261. build ( scope) ?; 262 registry. set ( scope, key. into (), function. into ()) ?; 263} 264 registry. set_integrity_level ( scope, v8:: IntegrityLevel :: Frozen ) ?; 265Some ( registry) 266} 267} 268 269enum OpError { 270Type ( String ), 271Error ( String ), 272} 273 274impl OpError { 275fn exception < ' s >( & self , scope : & mut v8:: PinScope < ' s , ' _ >) -> v8:: Local < ' s , v8:: Value > { 276let ( is_type_error, message) =match self { 277Self :: Type ( message) =>( true , message), 278Self :: Error ( message) =>( false , message), 279}; 280let message = v8:: String :: new ( scope, message). unwrap (); 281if is_type_error{ 282 v8:: Exception :: type_error ( scope, message) 283} else { 284 v8:: Exception :: error ( scope, message) 285} 286} 287} 288 289impl Op { 290/// Receives all positional JavaScript arguments without deserialization. 291pub fn raw < F >( name : &' static str , function : F ) ->Self 292where 293F : for < ' s , ' i > Fn ( 294& mut v8:: PinScope < ' s , ' i >, 295 v8:: FunctionCallbackArguments < ' s >, 296) ->Option < v8:: Local < ' s , v8:: Value >> 297 +' static , 298{ 299Self { 300 name, 301callback : Box :: new ( function), 302} 303} 304 305/// A positional op that returns V8 values directly and throws host errors. 306pub fn try_raw < E >( 307name : &' static str , 308function : impl for < ' s , ' i > Fn ( 309& mut v8:: PinScope < ' s , ' i >, 310 v8:: FunctionCallbackArguments < ' s >, 311) ->Result < v8:: Local < ' s , v8:: Value >, E > 312 +' static , 313) ->Self 314where 315E : std:: error:: Error , 316{ 317Self :: with_callback ( name, move |scope, args|{ 318function ( scope, args). map_err ( |error|OpError :: Error ( error. to_string ())) 319}) 320} 321 322fn with_callback ( 323name : &' static str , 324function : impl for < ' s , ' i > Fn ( 325& mut v8:: PinScope < ' s , ' i >, 326 v8:: FunctionCallbackArguments < ' s >, 327) ->Result < v8:: Local < ' s , v8:: Value >, OpError > 328 +' static , 329) ->Self { 330Self :: raw ( name, move |scope, args|match function ( scope, args) { 331Ok ( value) =>Some ( value), 332Err ( error) =>{ 333let exception = error. exception ( scope); 334 scope. throw_exception ( exception); 335None 336} 337}) 338} 339 340pub fn new < A , R , E >( name : &' static str , function : impl Fn ( A ) ->Result < R , E > +' static ) ->Self 341where 342A : DeserializeOwned , 343R : Serialize , 344E : std:: error:: Error , 345{ 346Self :: with_scope ( name, move |_, args|function ( args)) 347} 348 349/// A typed op with access to the caller's V8 scope. Pending JavaScript exceptions 350/// propagate to the caller; returning `Err` replaces them with a host error. 351pub fn with_scope < A , R , E >( 352name : &' static str , 353function : impl for < ' s , ' i > Fn ( & mut v8:: PinScope < ' s , ' i >, A ) ->Result < R , E > +' static , 354) ->Self 355where 356A : DeserializeOwned , 357R : Serialize , 358E : std:: error:: Error , 359{ 360Self :: with_callback ( name, move |scope, args|{ 361let args = serde_v8:: from_v8 ( scope, args. get ( 0 )) 362. map_err ( |error|OpError :: Type ( error. to_string ())) ?; 363let result = 364function ( scope, args). map_err ( |error|OpError :: Error ( error. to_string ())) ?; 365 serde_v8:: to_v8 ( scope, result). map_err ( |error|OpError :: Error ( error. to_string ())) 366}) 367} 368 369pub fn asynchronous < A , R , E , F >( name : &' static str , function : impl Fn ( A ) ->F +' static ) ->Self 370where 371A : DeserializeOwned , 372R : Serialize +' static , 373E : std:: error:: Error +' static , 374F : Future < Output =Result < R , E >> +' static , 375{ 376Self :: asynchronous_with_liveness ( name, function, true ) 377} 378 379pub fn asynchronous_unreferenced < A , R , E , F >( 380name : &' static str , 381function : impl Fn ( A ) ->F +' static , 382) ->Self 383where 384A : DeserializeOwned , 385R : Serialize +' static , 386E : std:: error:: Error +' static , 387F : Future < Output =Result < R , E >> +' static , 388{ 389Self :: asynchronous_with_liveness ( name, function, false ) 390} 391 392fn asynchronous_with_liveness < A , R , E , F >( 393name : &' static str , 394function : impl Fn ( A ) ->F +' static , 395referenced : bool , 396) ->Self 397where 398A : DeserializeOwned , 399R : Serialize +' static , 400E : std:: error:: Error +' static , 401F : Future < Output =Result < R , E >> +' static , 402{ 403Self :: with_callback ( name, move |scope, args|{ 404let args = serde_v8:: from_v8 ( scope, args. get ( 0 )) 405. map_err ( |error|OpError :: Type ( error. to_string ())) ?; 406let future =function ( args); 407let resolver = v8:: PromiseResolver :: new ( scope). unwrap (); 408let promise = resolver. get_promise ( scope); 409let resolver = v8:: Global :: new ( scope, resolver); 410let pending = scope. get_slot ::< Rc < RefCell < PendingOps >>>(). unwrap (). clone (); 411let mut pending = pending. borrow_mut (); 412if referenced{ 413 pending. referenced +=1 ; 414} 415 pending. futures . push ( Pending :: Op ( Some ( OpCompletion { 416future : Box :: pin ( OpFuture { 417future : futures:: future:: maybe_done ( future), 418 resolver, 419}), 420 referenced, 421}))); 422drop ( pending); 423if let Some ( waker) = scope. get_slot ::< std:: task:: Waker >() { 424 waker. wake_by_ref (); 425} 426Ok ( promise. into ()) 427}) 428} 429} 430 431pub ( crate ) fn clear ( isolate : & mut v8:: Isolate ) { 432 isolate. remove_slot ::< Rc < RefCell < PendingOps >>>(); 433 isolate. remove_slot ::< Rejections >(); 434 isolate. remove_slot ::< HandledRejections >(); 435} 436 437pub ( crate ) fn init ( isolate : & mut v8:: Isolate ) { 438 isolate. set_slot ::< Rejections >( Rc :: new ( RefCell :: new ( Vec :: new ()))); 439 isolate. set_slot ::< HandledRejections >( Rc :: new ( RefCell :: new ( Vec :: new ()))); 440 isolate. set_promise_reject_callback ( promise_rejected); 441 isolate. set_slot ::< Rc < RefCell < PendingOps >>>( Rc :: new ( RefCell :: new ( PendingOps { 442futures : FuturesUnordered :: new (), 443referenced : 0 , 444}))); 445} 446 447pub ( crate ) fn enqueue_import ( 448scope : & mut v8:: PinScope , 449future : LocalBoxFuture < ' static , crate :: modules:: ImportPreparation >, 450) { 451let pending = scope. get_slot ::< Rc < RefCell < PendingOps >>>(). unwrap (). clone (); 452let mut pending = pending. borrow_mut (); 453 pending. referenced +=1 ; 454 pending. futures . push ( Pending :: Import ( future)); 455drop ( pending); 456if let Some ( waker) = scope. get_slot ::< std:: task:: Waker >() { 457 waker. wake_by_ref (); 458} 459} 460 461pub ( crate ) fn process_rejections ( scope : & mut v8:: PinScope ) ->Option < v8:: Global < v8:: Value >> { 462let handled = scope. get_slot ::< HandledRejections >(). unwrap (). clone (); 463let reports = handled. borrow_mut (). drain ( ..). collect ::< Vec < _ >>(); 464for ( promise, reason) in reports{ 465crate :: reporting:: report_rejection_handled ( 466 scope, 467 v8:: Local :: new ( scope, & promise), 468 v8:: Local :: new ( scope, & reason), 469); 470} 471let rejections = scope. get_slot ::< Rejections >(). unwrap (). clone (); 472 rejections 473. borrow_mut () 474. retain ( |rejection|match & rejection. promise { 475RejectionPromise :: Pending ( _) =>true , 476RejectionPromise :: Reported ( weak) => !weak. is_empty (), 477}); 478let mut fatal =None ; 479loop { 480let ( promise, reason) ={ 481let rejections = rejections. borrow (); 482let Some ( rejection) = rejections 483. iter () 484. find ( |rejection|matches! ( rejection. promise , RejectionPromise :: Pending ( _))) 485else { 486break ; 487}; 488let RejectionPromise :: Pending ( promise) =& rejection. promise else { 489unreachable! (); 490}; 491( promise. clone (), rejection. reason . as_ref (). unwrap (). clone ()) 492}; 493let promise_local = v8:: Local :: new ( scope, & promise); 494let reason_local = v8:: Local :: new ( scope, & reason); 495let canceled = 496crate :: reporting:: report_unhandled_rejection ( scope, promise_local, reason_local); 497let weak = v8:: Weak :: new ( scope, promise_local); 498let mut rejections = rejections. borrow_mut (); 499let Some ( rejection) = rejections. iter_mut (). find ( |rejection|{ 500matches! ( & rejection. promise , RejectionPromise :: Pending ( promise) if v8:: Local :: new ( scope, promise) == promise_local) 501}) else { 502continue ; 503}; 504 rejection. promise =RejectionPromise :: Reported ( weak); 505 rejection. reason . take (); 506drop ( rejections); 507if !canceled && fatal. is_none () { 508 fatal =Some ( reason); 509} 510} 511if let Some ( error) =& fatal{ 512crate :: reporting:: suppress_exception ( scope, v8:: Local :: new ( scope, error)); 513} 514 fatal 515} 516 517pub ( crate ) fn checkpoint ( scope : & mut v8:: PinScope ) { 518loop { 519 scope. perform_microtask_checkpoint (); 520if !v8:: Platform :: pump_message_loop ( & v8:: V8 :: get_current_platform (), scope, false ) { 521break ; 522} 523} 524} 525 526pub ( crate ) fn has_pending_work ( isolate : & v8:: Isolate ) ->bool { 527 !isolate 528. get_slot ::< Rc < RefCell < PendingOps >>>() 529. unwrap () 530. borrow () 531. futures 532. is_empty () 533} 534 535pub ( crate ) fn poll_event_loop ( scope : & mut v8:: PinScope , context : & mut Context < ' _ >) ->Option < bool > { 536if crate :: tasks:: run_next ( scope) ?{ 537return Some ( true ); 538} 539let pending = scope. get_slot ::< Rc < RefCell < PendingOps >>>(). unwrap (). clone (); 540let completion = pending. borrow_mut (). futures . poll_next_unpin ( context); 541let Poll :: Ready ( Some ( completion)) = completionelse { 542return Some ( false ); 543}; 544 545match completion{ 546Completion :: Import ( preparation) =>{ 547 pending. borrow_mut (). referenced -=1 ; 548crate :: modules:: import_prepared ( scope, preparation); 549} 550Completion :: Op ( mut completion) =>{ 551if completion. referenced { 552 pending. borrow_mut (). referenced -=1 ; 553} 554 completion. future . as_mut (). complete ( scope); 555} 556} 557Some ( true ) 558} 559 560pub ( crate ) fn run_event_loop ( 561scope : & mut v8:: PinScope , 562promise : Option < v8:: Local < v8:: Promise >>, 563wait_for_idle : bool , 564) ->Option <()> { 565let pending = scope. get_slot ::< Rc < RefCell < PendingOps >>>(). unwrap (). clone (); 566loop { 567checkpoint ( scope); 568if scope. is_execution_terminating () { 569return None ; 570} 571if let Some ( error) =crate :: microtasks:: process_exceptions ( scope) { 572let error = v8:: Local :: new ( scope, error); 573crate :: reporting:: mark_processed_exception ( scope, error); 574 scope. throw_exception ( error); 575return None ; 576} 577if let Some ( promise) = promise 578 && promise. state () == v8:: PromiseState :: Rejected 579{ 580let error = promise. result ( scope); 581crate :: reporting:: report_exception_for_value ( scope, error); 582crate :: reporting:: mark_processed_exception ( scope, error); 583 scope. throw_exception ( error); 584return None ; 585} 586if let Some ( error) =process_rejections ( scope) { 587let error = v8:: Local :: new ( scope, error); 588 scope. throw_exception ( error); 589return None ; 590} 591if !wait_for_idle 592 && promise. is_some_and ( |promise| promise. state () == v8:: PromiseState :: Fulfilled ) 593{ 594return Some (()); 595} 596if crate :: tasks:: run_next ( scope) ?{ 597continue ; 598} 599let completion =if pending. borrow (). referenced ==0 { 600let mut pending = pending. borrow_mut (); 601let Some ( completion) = pending. futures . next (). now_or_never (). flatten () else { 602return match promise. map ( |promise| promise. state ()) { 603None |Some ( v8:: PromiseState :: Fulfilled ) =>Some (()), 604 _ =>{ 605let message = v8:: String :: new ( 606 scope, 607"Module evaluation is still pending with no runnable host work" , 608) 609. unwrap (); 610let error = v8:: Exception :: error ( scope, message); 611 scope. throw_exception ( error); 612None 613} 614}; 615}; 616 completion 617} else { 618 futures:: executor:: block_on ( pending. borrow_mut (). futures . next ()). unwrap () 619}; 620let mut completion =match completion{ 621Completion :: Op ( completion) => completion, 622Completion :: Import ( preparation) =>{ 623 pending. borrow_mut (). referenced -=1 ; 624crate :: modules:: import_prepared ( scope, preparation); 625continue ; 626} 627}; 628if completion. referenced { 629 pending. borrow_mut (). referenced -=1 ; 630} 631 completion. future . as_mut (). complete ( scope); 632} 633} 634 635fn dispatch < ' s >( 636scope : & mut v8:: PinScope < ' s , ' _ >, 637args : v8:: FunctionCallbackArguments < ' s >, 638mut result : v8:: ReturnValue , 639) { 640// Retain the closures across guest reentrancy without borrowing the isolate slot. 641let ops = scope. get_slot ::< RegisteredOps >(). cloned (); 642let op = v8:: Local ::< v8:: Uint32 >:: try_from ( args. data ()) 643. ok () 644. and_then ( |index| ops. as_ref () ?. ops . get ( index. value () as usize )); 645let Some ( op) = opelse { 646let error =OpError :: Error ( "Op is not registered in this isolate" . into ()). exception ( scope); 647 scope. throw_exception ( error); 648return ; 649}; 650if let Some ( value) =( op. callback )( scope, args) { 651 result. set ( value); 652} 653} 654 655# [ cfg ( test )] 656mod tests;