1use std::ffi::c_void;
4use std::ptr::null;
5use std::ptr::null_mut;
6
7use crate::ArrayBuffer;
8use crate::Isolate;
9use crate::Local;
10use crate::PinScope;
11use crate::Value;
12use crate::WasmMemoryObject;
13use crate::WasmModuleObject;
14use crate::binding::const_memory_span_t;
15use crate::function::FunctionCallbackArguments;
16use crate::function::FunctionCallbackInfo;
17use crate::isolate::RealIsolate;
18use crate::scope::GetIsolate;
19use crate::scope::callback_scope;
20use crate::support::MapFnFrom;
21use crate::support::MapFnTo;
22use crate::support::Opaque;
23use crate::support::ToCFn;
24use crate::support::UnitType;
25use crate::support::char;
26
27#[repr(C)]
38struct WasmStreamingSharedPtr([*mut u8; 2]);
39
40#[repr(C)]
45pub struct WasmStreaming<const HAS_COMPILED_MODULE_BYTES: bool>(
46 WasmStreamingSharedPtr,
47);
48
49impl<const HAS_COMPILED_MODULE_BYTES: bool>
50 WasmStreaming<HAS_COMPILED_MODULE_BYTES>
51{
52 #[inline(always)]
54 pub fn on_bytes_received(&mut self, data: &[u8]) {
55 unsafe {
56 v8__WasmStreaming__OnBytesReceived(
57 &mut self.0,
58 data.as_ptr(),
59 data.len(),
60 );
61 }
62 }
63
64 #[inline(always)]
68 pub fn abort(mut self, exception: Option<Local<Value>>) {
69 let exception = exception.map_or(null(), |v| &*v as *const Value);
70 unsafe { v8__WasmStreaming__Abort(&mut self.0, exception) }
71 }
72
73 #[inline(always)]
76 pub fn set_url(&mut self, url: &str) {
77 let null_terminated_url = format!("{url}\0");
80 unsafe {
81 v8__WasmStreaming__SetUrl(
82 &mut self.0,
83 null_terminated_url.as_ptr() as *const char,
84 url.len(),
85 );
86 }
87 }
88}
89
90impl WasmStreaming<false> {
91 #[inline(always)]
99 pub fn finish(mut self) {
100 unsafe { v8__WasmStreaming__Finish(&mut self.0, None) }
101 }
102
103 #[inline(always)]
110 pub fn set_has_compiled_module_bytes(mut self) -> WasmStreaming<true> {
111 unsafe {
112 v8__WasmStreaming__SetHasCompiledModuleBytes(&mut self.0);
113 std::mem::transmute(self)
114 }
115 }
116}
117
118impl WasmStreaming<true> {
119 #[inline(always)]
127 pub fn finish<F>(mut self, f: F)
128 where
129 F: MapFnTo<ModuleCachingCallback>,
130 {
131 unsafe { v8__WasmStreaming__Finish(&mut self.0, Some(f.map_fn_to())) }
132 }
133}
134
135impl<const HAS_COMPILED_MODULE_BYTES: bool> Drop
136 for WasmStreaming<HAS_COMPILED_MODULE_BYTES>
137{
138 fn drop(&mut self) {
139 unsafe { v8__WasmStreaming__shared_ptr_DESTRUCT(&mut self.0) }
140 }
141}
142
143impl WasmModuleObject {
144 #[inline(always)]
147 pub fn from_compiled_module<'s>(
148 scope: &PinScope<'s, '_>,
149 compiled_module: &CompiledWasmModule,
150 ) -> Option<Local<'s, WasmModuleObject>> {
151 unsafe {
152 scope.cast_local(|sd| {
153 v8__WasmModuleObject__FromCompiledModule(
154 sd.get_isolate_ptr(),
155 compiled_module.0,
156 )
157 })
158 }
159 }
160
161 #[inline(always)]
164 pub fn get_compiled_module(&self) -> CompiledWasmModule {
165 let ptr = unsafe { v8__WasmModuleObject__GetCompiledModule(self) };
166 CompiledWasmModule(ptr)
167 }
168
169 #[inline(always)]
171 pub fn compile<'s>(
172 scope: &PinScope<'s, '_>,
173 wire_bytes: &[u8],
174 ) -> Option<Local<'s, WasmModuleObject>> {
175 unsafe {
176 scope.cast_local(|sd| {
177 v8__WasmModuleObject__Compile(
178 sd.get_isolate_ptr(),
179 wire_bytes.as_ptr(),
180 wire_bytes.len(),
181 )
182 })
183 }
184 }
185}
186
187#[repr(C)]
188pub struct ModuleCachingInterface(Opaque);
189
190impl ModuleCachingInterface {
191 #[inline(always)]
193 pub fn get_wire_bytes(&self) -> &[u8] {
194 unsafe {
195 let span = v8__ModuleCachingInterface__GetWireBytes(self);
196 std::slice::from_raw_parts(span.data, span.size)
197 }
198 }
199
200 #[inline(always)]
208 pub fn set_cached_compiled_module_bytes(&mut self, bytes: &[u8]) -> bool {
209 unsafe {
210 v8__ModuleCachingInterface__SetCachedCompiledModuleBytes(
211 self,
212 const_memory_span_t {
213 data: bytes.as_ptr(),
214 size: bytes.len(),
215 },
216 )
217 }
218 }
219}
220
221pub type ModuleCachingCallback =
222 unsafe extern "C" fn(*mut ModuleCachingInterface);
223
224impl<F> MapFnFrom<F> for ModuleCachingCallback
225where
226 F: UnitType + Fn(&mut ModuleCachingInterface),
227{
228 fn mapping() -> Self {
229 let f = |mci: *mut ModuleCachingInterface| {
230 (F::get())(unsafe { &mut *mci });
231 };
232 f.to_c_fn()
233 }
234}
235
236#[repr(C)]
243struct InternalCompiledWasmModule(Opaque);
244
245pub struct CompiledWasmModule(*mut InternalCompiledWasmModule);
248
249impl CompiledWasmModule {
250 #[inline(always)]
252 pub fn get_wire_bytes_ref(&self) -> &[u8] {
253 let mut len = 0isize;
254 unsafe {
255 let ptr = v8__CompiledWasmModule__GetWireBytesRef(self.0, &mut len);
256 std::slice::from_raw_parts(ptr, len.try_into().unwrap())
257 }
258 }
259
260 #[inline(always)]
261 pub fn source_url(&self) -> &str {
262 let mut len = 0;
263 unsafe {
264 let ptr = v8__CompiledWasmModule__SourceUrl(self.0, &mut len);
265 let bytes = std::slice::from_raw_parts(ptr as _, len);
266 std::str::from_utf8_unchecked(bytes)
267 }
268 }
269}
270
271unsafe impl Send for CompiledWasmModule {}
273unsafe impl Sync for CompiledWasmModule {}
274
275impl Drop for CompiledWasmModule {
276 fn drop(&mut self) {
277 unsafe { v8__CompiledWasmModule__DELETE(self.0) }
278 }
279}
280
281#[repr(C)]
283struct InternalWasmModuleCompilation(Opaque);
284
285pub struct WasmModuleCompilation(*mut InternalWasmModuleCompilation);
291
292unsafe impl Send for WasmModuleCompilation {}
294
295impl WasmModuleCompilation {
296 #[inline(always)]
299 pub fn new() -> Self {
300 unsafe { WasmModuleCompilation(v8__WasmModuleCompilation__NEW()) }
301 }
302
303 #[inline(always)]
307 pub fn on_bytes_received(&mut self, data: &[u8]) {
308 unsafe {
309 v8__WasmModuleCompilation__OnBytesReceived(
310 self.0,
311 data.as_ptr(),
312 data.len(),
313 );
314 }
315 }
316
317 #[inline(always)]
327 pub fn finish(
328 self,
329 scope: &mut PinScope,
330 caching_callback: Option<ModuleCachingCallback>,
331 resolution_callback: impl FnOnce(
332 &Isolate,
333 Result<Local<'_, WasmModuleObject>, Local<'_, Value>>,
334 ) + 'static,
335 ) {
336 let isolate_ptr = scope.get_isolate_ptr();
339 let wrapped = move |module: *const WasmModuleObject,
340 error: *const Value| {
341 let isolate = unsafe { Isolate::from_raw_ptr(isolate_ptr) };
342 if !module.is_null() {
343 resolution_callback(
344 &isolate,
345 Ok(unsafe { Local::from_raw(module) }.unwrap()),
346 );
347 } else {
348 resolution_callback(
349 &isolate,
350 Err(unsafe { Local::from_raw(error) }.unwrap()),
351 );
352 }
353 };
354
355 #[allow(clippy::type_complexity)]
360 let boxed: Box<
361 Option<Box<dyn FnOnce(*const WasmModuleObject, *const Value)>>,
362 > = Box::new(Some(Box::new(wrapped)));
363 let data = Box::into_raw(boxed) as *mut c_void;
364
365 unsafe {
366 v8__WasmModuleCompilation__Finish(
367 self.0,
368 scope.get_isolate_ptr(),
369 caching_callback,
370 resolution_trampoline,
371 data,
372 drop_resolution_data,
373 );
374 }
375 }
376
377 #[inline(always)]
380 pub fn abort(self) {
381 unsafe { v8__WasmModuleCompilation__Abort(self.0) }
382 }
383
384 #[inline(always)]
389 pub fn set_has_compiled_module_bytes(&mut self) {
390 unsafe {
391 v8__WasmModuleCompilation__SetHasCompiledModuleBytes(self.0);
392 }
393 }
394
395 #[inline(always)]
398 pub fn set_more_functions_can_be_serialized_callback(
399 &mut self,
400 callback: impl Fn(CompiledWasmModule) + Send + 'static,
401 ) {
402 let boxed: Box<Box<dyn Fn(CompiledWasmModule) + Send>> =
403 Box::new(Box::new(callback));
404 let data = Box::into_raw(boxed) as *mut c_void;
405
406 unsafe {
407 v8__WasmModuleCompilation__SetMoreFunctionsCanBeSerializedCallback(
408 self.0,
409 serialization_trampoline,
410 data,
411 drop_serialization_data,
412 );
413 }
414 }
415
416 #[inline(always)]
419 pub fn set_url(&mut self, url: &str) {
420 let null_terminated_url = format!("{url}\0");
422 unsafe {
423 v8__WasmModuleCompilation__SetUrl(
424 self.0,
425 null_terminated_url.as_ptr() as *const char,
426 url.len(),
427 );
428 }
429 }
430}
431
432impl Default for WasmModuleCompilation {
433 fn default() -> Self {
434 Self::new()
435 }
436}
437
438impl Drop for WasmModuleCompilation {
439 fn drop(&mut self) {
440 unsafe { v8__WasmModuleCompilation__DELETE(self.0) }
441 }
442}
443
444unsafe extern "C" fn resolution_trampoline(
445 data: *mut c_void,
446 module: *const WasmModuleObject,
447 error: *const Value,
448) {
449 let slot = unsafe {
453 &mut *(data
454 as *mut Option<Box<dyn FnOnce(*const WasmModuleObject, *const Value)>>)
455 };
456 let callback = slot.take().unwrap();
457 callback(module, error);
458}
459
460unsafe extern "C" fn drop_resolution_data(data: *mut c_void) {
461 let _ = unsafe {
462 Box::from_raw(
463 data
464 as *mut Option<Box<dyn FnOnce(*const WasmModuleObject, *const Value)>>,
465 )
466 };
467}
468
469unsafe extern "C" fn serialization_trampoline(
470 data: *mut c_void,
471 compiled_module: *mut InternalCompiledWasmModule,
472) {
473 let callback =
474 unsafe { &**(data as *const Box<dyn Fn(CompiledWasmModule) + Send>) };
475 callback(CompiledWasmModule(compiled_module));
476}
477
478unsafe extern "C" fn drop_serialization_data(data: *mut c_void) {
479 let _ = unsafe {
480 Box::from_raw(data as *mut Box<dyn Fn(CompiledWasmModule) + Send>)
481 };
482}
483
484impl WasmMemoryObject {
485 #[inline(always)]
487 pub fn buffer(&self) -> Local<'_, ArrayBuffer> {
488 unsafe { Local::from_raw(v8__WasmMemoryObject__Buffer(self)) }.unwrap()
489 }
490}
491
492pub(crate) fn trampoline<F>()
493-> unsafe extern "C" fn(*const FunctionCallbackInfo)
494where
495 F: UnitType
496 + for<'a, 'b, 'c> Fn(
497 &'c mut PinScope<'a, 'b>,
498 Local<'a, Value>,
499 WasmStreaming<false>,
500 ),
501{
502 unsafe extern "C" fn c_fn<F>(info: *const FunctionCallbackInfo)
503 where
504 F: UnitType
505 + for<'a, 'b, 'c> Fn(
506 &'c mut PinScope<'a, 'b>,
507 Local<'a, Value>,
508 WasmStreaming<false>,
509 ),
510 {
511 let info = unsafe { &*info };
512 callback_scope!(unsafe scope, info);
513 let args = FunctionCallbackArguments::from_function_callback_info(info);
514 let data = args.data();
515 let zero = null_mut();
516 let mut that = WasmStreamingSharedPtr([zero, zero]);
517 unsafe {
518 v8__WasmStreaming__Unpack(scope.get_isolate_ptr(), &*data, &mut that);
519 };
520 let source = args.get(0);
521 (F::get())(scope, source, WasmStreaming(that));
522 }
523 c_fn::<F>
524}
525
526unsafe extern "C" {
527 fn v8__WasmStreaming__Unpack(
528 isolate: *mut RealIsolate,
529 value: *const Value,
530 that: *mut WasmStreamingSharedPtr, );
532 fn v8__WasmStreaming__shared_ptr_DESTRUCT(this: *mut WasmStreamingSharedPtr);
533 fn v8__WasmStreaming__SetHasCompiledModuleBytes(
534 this: *mut WasmStreamingSharedPtr,
535 );
536 fn v8__WasmStreaming__OnBytesReceived(
537 this: *mut WasmStreamingSharedPtr,
538 data: *const u8,
539 len: usize,
540 );
541 fn v8__WasmStreaming__Finish(
542 this: *mut WasmStreamingSharedPtr,
543 callback: Option<ModuleCachingCallback>,
544 );
545 fn v8__WasmStreaming__Abort(
546 this: *mut WasmStreamingSharedPtr,
547 exception: *const Value,
548 );
549 fn v8__WasmStreaming__SetUrl(
550 this: *mut WasmStreamingSharedPtr,
551 url: *const char,
552 len: usize,
553 );
554
555 fn v8__ModuleCachingInterface__GetWireBytes(
556 interface: *const ModuleCachingInterface,
557 ) -> const_memory_span_t;
558 fn v8__ModuleCachingInterface__SetCachedCompiledModuleBytes(
559 interface: *mut ModuleCachingInterface,
560 bytes: const_memory_span_t,
561 ) -> bool;
562
563 fn v8__WasmModuleObject__FromCompiledModule(
564 isolate: *mut RealIsolate,
565 compiled_module: *const InternalCompiledWasmModule,
566 ) -> *const WasmModuleObject;
567 fn v8__WasmModuleObject__GetCompiledModule(
568 this: *const WasmModuleObject,
569 ) -> *mut InternalCompiledWasmModule;
570 fn v8__WasmModuleObject__Compile(
571 isolate: *mut RealIsolate,
572 wire_bytes_data: *const u8,
573 length: usize,
574 ) -> *mut WasmModuleObject;
575
576 fn v8__CompiledWasmModule__GetWireBytesRef(
577 this: *mut InternalCompiledWasmModule,
578 length: *mut isize,
579 ) -> *const u8;
580 fn v8__CompiledWasmModule__SourceUrl(
581 this: *mut InternalCompiledWasmModule,
582 length: *mut usize,
583 ) -> *const char;
584 fn v8__CompiledWasmModule__DELETE(this: *mut InternalCompiledWasmModule);
585
586 fn v8__WasmMemoryObject__Buffer(
587 this: *const WasmMemoryObject,
588 ) -> *mut ArrayBuffer;
589
590 fn v8__WasmModuleCompilation__NEW() -> *mut InternalWasmModuleCompilation;
591 fn v8__WasmModuleCompilation__DELETE(
592 this: *mut InternalWasmModuleCompilation,
593 );
594 fn v8__WasmModuleCompilation__OnBytesReceived(
595 this: *mut InternalWasmModuleCompilation,
596 bytes: *const u8,
597 size: usize,
598 );
599 fn v8__WasmModuleCompilation__Finish(
600 this: *mut InternalWasmModuleCompilation,
601 isolate: *mut RealIsolate,
602 caching_callback: Option<ModuleCachingCallback>,
603 resolution_callback: unsafe extern "C" fn(
604 *mut c_void,
605 *const WasmModuleObject,
606 *const Value,
607 ),
608 resolution_data: *mut c_void,
609 drop_resolution_data: unsafe extern "C" fn(*mut c_void),
610 );
611 fn v8__WasmModuleCompilation__Abort(this: *mut InternalWasmModuleCompilation);
612 fn v8__WasmModuleCompilation__SetHasCompiledModuleBytes(
613 this: *mut InternalWasmModuleCompilation,
614 );
615 fn v8__WasmModuleCompilation__SetMoreFunctionsCanBeSerializedCallback(
616 this: *mut InternalWasmModuleCompilation,
617 callback: unsafe extern "C" fn(
618 *mut c_void,
619 *mut InternalCompiledWasmModule,
620 ),
621 data: *mut c_void,
622 drop_data: unsafe extern "C" fn(*mut c_void),
623 );
624 fn v8__WasmModuleCompilation__SetUrl(
625 this: *mut InternalWasmModuleCompilation,
626 url: *const char,
627 length: usize,
628 );
629}