char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
05d50bd
main
1use std:: cell:: RefCell ; 2use std:: collections::{ HashMap , HashSet }; 3use std:: rc:: Rc ; 4use std:: task:: Poll ; 5 6use avril_core::{ Error , ModuleLoader , ModuleSource , Runtime , RuntimeOptions }; 7use futures:: future:: LocalBoxFuture ; 8 9struct AcquiringLoader { 10sources : HashMap < String , ModuleSource >, 11ready : Rc < RefCell < HashSet < String >>>, 12} 13 14impl ModuleLoader for AcquiringLoader { 15fn resolve ( & self , specifier : & str , _: & str ) ->Result < String , Error > { 16Ok ( specifier. trim_start_matches ( "./" ). to_owned ()) 17} 18 19fn load ( & self , name : & str ) ->Result < ModuleSource , Error > { 20if !self . ready . borrow (). contains ( name) { 21return Err ( Error :: Module ( 22"V8 linked before acquisition completed" . into (), 23)); 24} 25self . sources 26. get ( name) 27. cloned () 28. ok_or_else ( ||Error :: Module ( "Missing source" . into ())) 29} 30 31fn prepare ( 32& self , 33specifier : String , 34referrer : String , 35) ->LocalBoxFuture < ' static , Result < String , Error >> { 36let name =if referrer. is_empty () { 37 specifier 38} else { 39self . resolve ( & specifier, & referrer). unwrap () 40}; 41let ready =self . ready . clone (); 42let mut yielded =false ; 43Box :: pin ( futures:: future:: poll_fn ( move |cx|{ 44if !yielded{ 45 yielded =true ; 46 cx. waker (). wake_by_ref (); 47return Poll :: Pending ; 48} 49if name =="missing.js" { 50return Poll :: Ready ( Err ( Error :: Module ( "Acquisition failed" . into ()))); 51} 52 ready. borrow_mut (). insert ( name. clone ()); 53if name =="dep.js" { 54 ready. borrow_mut (). insert ( "static.js" . into ()); 55} 56Poll :: Ready ( Ok ( name. clone ())) 57})) 58} 59} 60 61# [ test ] 62fn asynchronous_preparation_precedes_linking_for_entries_and_computed_imports () { 63let sources =[ 64( 65"main.js" , 66r#" 67const name = './' + 'dep.js'; 68const [a, b] = await Promise.all([import(name), import(name)]); 69globalThis.result = [a === b, a.value, a.count, a.main]; 70try { await import('./missing.js'); } catch(e) { globalThis.failure = e.message; } 71globalThis.again = (await import(name)) === a; 72"# , 73), 74( 75"dep.js" , 76r#" 77import {value} from './static.js'; 78export {value}; 79export const count = globalThis.count = (globalThis.count ?? 0) + 1; 80export const main = import.meta.main; 81"# , 82), 83( "static.js" , "export const value = 42;" ), 84] 85. into_iter () 86. map ( |( name, source) |( name. into (), source. into ())) 87. collect (); 88let mut runtime =Runtime :: new ( RuntimeOptions { 89module_loader : Some ( Rc :: new ( AcquiringLoader { sources, ready : Rc :: default () })), 90 ..Default :: default () 91}) 92. unwrap (); 93 runtime. execute_module ( "main.js" ). unwrap (); 94let result: ( bool , u32 , u32 , bool ) = runtime. execute_script ( "result" , "result" ). unwrap (); 95assert_eq! ( result, ( true , 42 , 1 , false )); 96assert_eq! ( 97 runtime 98. execute_script ::< String >( "failure" , "failure" ) 99. unwrap (), 100"Acquisition failed" 101); 102assert! ( runtime. execute_script ::< bool >( "again" , "again" ). unwrap ()); 103} 104 105# [ test ] 106fn started_modules_allow_host_progress_during_top_level_await () { 107for rejectin [ false , true ] { 108let source =format! ( 109"await new Promise(resolve => globalThis.resume = resolve); {}" , 110if reject{ 111"throw Error('entry rejection');" 112} else { 113"globalThis.result = 42;" 114} 115); 116let mut runtime =Runtime :: new ( RuntimeOptions { 117module_loader : Some ( Rc :: new ( AcquiringLoader { 118sources : HashMap :: from ([( "main.js" . into (), source. into ())]), 119ready : Rc :: default (), 120})), 121 ..Default :: default () 122}) 123. unwrap (); 124 runtime. start_module ( "main.js" ). unwrap (); 125assert! ( runtime. has_pending_work ()); 126assert! ( runtime. start_module ( "main.js" ). is_err ()); 127 runtime. execute_script ::<()>( "resume" , "resume()" ). unwrap (); 128let mut context = std:: task:: Context :: from_waker ( futures:: task:: noop_waker_ref ()); 129let polled = runtime. poll_event_loop ( & mut context); 130if reject{ 131assert! ( polled. unwrap_err (). to_string (). contains ( "entry rejection" )); 132} else { 133 polled. unwrap (); 134assert_eq! ( 135 runtime. execute_script ::< u32 >( "result" , "result" ). unwrap (), 13642 137); 138} 139assert! ( !runtime. has_pending_work ()); 140} 141}