char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
cc2165a
main
1use std:: any:: Any ; 2use std:: cell:: RefCell ; 3use std:: io; 4use std:: rc:: Rc ; 5use std:: sync:: Arc ; 6 7use bytes:: Bytes ; 8use v8::{ ValueDeserializerHelper , ValueSerializerHelper }; 9 10# [ derive ( Default )] 11pub struct Message { 12bytes : Bytes , 13has_transfers : bool , 14buffers : Vec < v8:: SharedRef < v8:: BackingStore >>, 15shared : Vec < v8:: SharedRef < v8:: BackingStore >>, 16modules : Vec < Arc < v8:: CompiledWasmModule >>, 17host_payloads : Vec < Arc < dyn Any +Send +Sync >>, 18} 19 20impl Message { 21pub fn try_clone ( & self ) ->Option < Self > { 22if self . has_transfers { 23return None ; 24} 25Some ( Self { 26bytes : self . bytes . clone (), 27has_transfers : false , 28buffers : Vec :: new (), 29shared : self . shared . clone (), 30modules : self . modules . clone (), 31host_payloads : self . host_payloads . clone (), 32}) 33} 34} 35 36# [ derive ( Clone , Copy , PartialEq , Eq )] 37enum Direction { 38Encode , 39Decode , 40} 41 42# [ derive ( Clone )] 43struct HostContext { 44message : Rc < RefCell < Message >>, 45direction : Direction , 46} 47 48type HostSlot =Rc < RefCell < Option < HostContext >>>; 49 50struct HostScope { 51slot : HostSlot , 52previous : Option < HostContext >, 53} 54 55impl Drop for HostScope { 56fn drop ( & mut self ) { 57self . slot . replace ( self . previous . take ()); 58} 59} 60 61fn current_message ( scope : & v8:: PinScope , direction : Direction ) -> io:: Result < Rc < RefCell < Message >>> { 62 scope 63. get_slot ::< HostSlot >() 64. and_then ( |slot|{ 65 slot. borrow () 66. as_ref () 67. filter ( |context| context. direction == direction) 68. map ( |context| context. message . clone ()) 69}) 70. ok_or_else ( || io:: Error :: other ( "No matching host serialization callback is active" )) 71} 72 73/// Carry an opaque Rust payload outside the byte stream during host encoding. 74pub fn serialize_host < T : Any +Send +Sync >( 75scope : & v8:: PinScope , 76payload : Arc < T >, 77) -> io:: Result < u32 > { 78let message =current_message ( scope, Direction :: Encode ) ?; 79let mut message = message. borrow_mut (); 80let id = u32:: try_from ( message. host_payloads . len ()) 81. map_err ( |_| io:: Error :: other ( "Too many host payloads" )) ?; 82 message. host_payloads . push ( payload); 83Ok ( id) 84} 85 86/// Recover an opaque Rust payload during host decoding, checking its type. 87pub fn deserialize_host < T : Any +Send +Sync >( scope : & v8:: PinScope , id : u32 ) -> io:: Result < Arc < T >> { 88current_message ( scope, Direction :: Decode ) ? 89. borrow () 90. host_payloads 91. get ( idas usize ) 92. cloned () 93. and_then ( |payload| payload. downcast (). ok ()) 94. ok_or_else ( || io:: Error :: other ( "Invalid host payload" )) 95} 96 97struct Policy { 98direction : Direction , 99classify : Option < v8:: Global < v8:: Function >>, 100host : v8:: Global < v8:: Function >, 101error : v8:: Global < v8:: Function >, 102message : Rc < RefCell < Message >>, 103} 104 105impl Policy { 106fn call_host < ' s >( 107& self , 108scope : & mut v8:: PinScope < ' s , ' _ >, 109value : v8:: Local < ' s , v8:: Value >, 110) ->Option < v8:: Local < ' s , v8:: Value >> { 111let slot = scope. get_slot ::< HostSlot >(). cloned (). unwrap_or_else ( ||{ 112let slot =HostSlot :: default (); 113 scope. set_slot ( slot. clone ()); 114 slot 115}); 116let previous = slot. replace ( Some ( HostContext { 117message : self . message . clone (), 118direction : self . direction , 119})); 120// Nested messaging must restore the outer callback's payload list, even on failure. 121let _guard =HostScope { slot, previous}; 122let callback = v8:: Local :: new ( scope, & self . host ); 123let receiver = v8:: undefined ( scope). into (); 124 callback. call ( scope, receiver, & [ value]) 125} 126 127fn fail ( & self , scope : & mut v8:: PinScope , message : & str ) { 128let message = v8:: String :: new ( scope, message). unwrap (); 129self . throw ( scope, message); 130} 131 132fn throw ( & self , scope : & mut v8:: PinScope , message : v8:: Local < v8:: String >) { 133let callback = v8:: Local :: new ( scope, & self . error ); 134let receiver = v8:: undefined ( scope). into (); 135if let Some ( error) = callback. call ( scope, receiver, & [ message. into ()]) { 136 scope. throw_exception ( error); 137} 138} 139} 140 141impl v8:: ValueSerializerImpl for & Policy { 142fn throw_data_clone_error < ' s >( 143& self , 144scope : & mut v8:: PinScope < ' s , ' _ >, 145message : v8:: Local < ' s , v8:: String >, 146) { 147self . throw ( scope, message); 148} 149 150fn has_custom_host_object ( & self , _: & v8:: Isolate ) ->bool { 151true 152} 153 154fn is_host_object < ' s >( 155& self , 156scope : & mut v8:: PinScope < ' s , ' _ >, 157object : v8:: Local < ' s , v8:: Object >, 158) ->Option < bool > { 159let callback = v8:: Local :: new ( scope, self . classify . as_ref () ?); 160let receiver = v8:: undefined ( scope). into (); 161Some ( 162 callback 163. call ( scope, receiver, & [ object. into ()]) ? 164. uint32_value ( scope) ? 165 !=0 , 166) 167} 168 169fn write_host_object < ' s >( 170& self , 171scope : & mut v8:: PinScope < ' s , ' _ >, 172object : v8:: Local < ' s , v8:: Object >, 173serializer : & dyn ValueSerializerHelper , 174) ->Option < bool > { 175let value =self . call_host ( scope, object. into ()) ?; 176 serializer. write_value ( scope. get_current_context (), value) 177} 178 179fn get_shared_array_buffer_id < ' s >( 180& self , 181scope : & mut v8:: PinScope < ' s , ' _ >, 182buffer : v8:: Local < ' s , v8:: SharedArrayBuffer >, 183) ->Option < u32 > { 184let mut message =self . message . borrow_mut (); 185let Ok ( id) = u32:: try_from ( message. shared . len ()) else { 186drop ( message); 187self . fail ( scope, "Too many shared buffers" ); 188return None ; 189}; 190 message. shared . push ( buffer. get_backing_store ()); 191Some ( id) 192} 193 194fn get_wasm_module_transfer_id ( 195& self , 196scope : & mut v8:: PinScope < ' _ , ' _ >, 197module : v8:: Local < v8:: WasmModuleObject >, 198) ->Option < u32 > { 199let mut message =self . message . borrow_mut (); 200let Ok ( id) = u32:: try_from ( message. modules . len ()) else { 201drop ( message); 202self . fail ( scope, "Too many WebAssembly modules" ); 203return None ; 204}; 205 message. modules . push ( Arc :: new ( module. get_compiled_module ())); 206Some ( id) 207} 208} 209 210impl v8:: ValueDeserializerImpl for & Policy { 211fn read_host_object < ' s >( 212& self , 213scope : & mut v8:: PinScope < ' s , ' _ >, 214deserializer : & dyn ValueDeserializerHelper , 215) ->Option < v8:: Local < ' s , v8:: Object >> { 216let value = deserializer. read_value ( scope. get_current_context ()) ?; 217// Host reconstruction calls trusted bootstrap code, not guest constructors. 218let allowed = std:: pin:: pin!( v8:: AllowJavascriptExecutionScope :: new ( scope)); 219let scope =& mut allowed. init (); 220 v8:: Local :: try_from ( self . call_host ( scope, value) ?). ok () 221} 222 223fn get_shared_array_buffer_from_id < ' s >( 224& self , 225scope : & mut v8:: PinScope < ' s , ' _ >, 226id : u32 , 227) ->Option < v8:: Local < ' s , v8:: SharedArrayBuffer >> { 228Some ( v8:: SharedArrayBuffer :: with_backing_store ( 229 scope, 230self . message . borrow (). shared . get ( idas usize ) ?, 231)) 232} 233 234fn get_wasm_module_from_id < ' s >( 235& self , 236scope : & mut v8:: PinScope < ' s , ' _ >, 237id : u32 , 238) ->Option < v8:: Local < ' s , v8:: WasmModuleObject >> { 239 v8:: WasmModuleObject :: from_compiled_module ( 240 scope, 241self . message . borrow (). modules . get ( idas usize ) ?, 242) 243} 244} 245 246/// Callbacks are isolate-local; the returned message contains no V8 handles. 247pub fn serialize < ' s >( 248scope : & mut v8:: PinScope < ' s , ' _ >, 249value : v8:: Local < ' s , v8:: Value >, 250transfer : v8:: Local < ' s , v8:: Array >, 251callbacks : [ v8:: Local < ' s , v8:: Function >; 5 ], 252) ->Option < Message > { 253let [ classify, host, error, validate, commit] = callbacks; 254let policy =Policy { 255direction : Direction :: Encode , 256classify : Some ( v8:: Global :: new ( scope, classify)), 257host : v8:: Global :: new ( scope, host), 258error : v8:: Global :: new ( scope, error), 259message : Rc :: new ( RefCell :: new ( Message { 260has_transfers : transfer. length () !=0 , 261 ..Default :: default () 262})), 263}; 264let mut buffers =Vec :: new (); 265let seen = v8:: Set :: new ( scope); 266for indexin 0 ..transfer. length () { 267let value = transfer. get_index ( scope, index) ?; 268if seen. has ( scope, value) ?{ 269 policy. fail ( scope, "Transfer list contains a duplicate value" ); 270return None ; 271} 272 seen. add ( scope, value) ?; 273if let Ok ( buffer) = v8:: Local ::< v8:: ArrayBuffer >:: try_from ( value) { 274 buffers. push ( buffer); 275} else { 276let receiver = v8:: undefined ( scope). into (); 277if classify 278. call ( scope, receiver, & [ value]) ? 279. uint32_value ( scope) ? 280 !=2 281{ 282 policy. fail ( scope, "Transfer list contains a non-transferable value" ); 283return None ; 284} 285} 286} 287let receiver = v8:: undefined ( scope). into (); 288 validate. call ( scope, receiver, & []) ?; 289let serializer = v8:: ValueSerializer :: new ( scope, Box :: new ( & policy)); 290for ( id, buffer) in buffers. iter (). enumerate () { 291 serializer. transfer_array_buffer ( idas u32 , * buffer); 292} 293 serializer. write_header (); 294if serializer. write_value ( scope. get_current_context (), value) !=Some ( true ) { 295return None ; 296} 297 validate. call ( scope, receiver, & []) ?; 298 policy. message . borrow_mut (). bytes = serializer. release (). into (); 299for bufferin buffers{ 300if buffer. was_detached () { 301 policy. fail ( scope, "Cannot transfer a detached ArrayBuffer" ); 302return None ; 303} 304if !buffer. is_detachable () { 305let message = v8:: String :: new ( scope, "Cannot detach this ArrayBuffer" ) ?; 306 scope. throw_exception ( v8:: Exception :: type_error ( scope, message)); 307return None ; 308} 309let store = buffer. get_backing_store (); 310if buffer. detach ( None ) !=Some ( true ) { 311return None ; 312} 313 policy. message . borrow_mut (). buffers . push ( store); 314} 315 commit. call ( scope, receiver, & []) ?; 316drop ( serializer); 317Some ( policy. message . take ()) 318} 319 320pub fn deserialize < ' s >( 321scope : & mut v8:: PinScope < ' s , ' _ >, 322mut message : Message , 323host : v8:: Local < ' s , v8:: Function >, 324error : v8:: Local < ' s , v8:: Function >, 325) ->Option < v8:: Local < ' s , v8:: Value >> { 326let bytes = std:: mem:: take ( & mut message. bytes ); 327let buffers = std:: mem:: take ( & mut message. buffers ); 328let policy =Policy { 329direction : Direction :: Decode , 330classify : None , 331host : v8:: Global :: new ( scope, host), 332error : v8:: Global :: new ( scope, error), 333message : Rc :: new ( RefCell :: new ( message)), 334}; 335let deserializer = v8:: ValueDeserializer :: new ( scope, Box :: new ( & policy), & bytes); 336for ( id, store) in buffers. iter (). enumerate () { 337let buffer = v8:: ArrayBuffer :: with_backing_store ( scope, store); 338 deserializer. transfer_array_buffer ( idas u32 , buffer); 339} 340let context = scope. get_current_context (); 341let value ={ 342 v8:: tc_scope!( let caught, scope); 343let value =if deserializer. read_header ( context) ==Some ( true ) { 344 deserializer. read_value ( context) 345} else { 346None 347}; 348if value. is_none () { 349 caught. reset (); 350} 351 value 352}; 353if value. is_none () { 354 policy. fail ( scope, "Cannot deserialize this message" ); 355} 356 value 357}