@@ -516,8 +516,17 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
516
516
// every PeristentObjet we've created during the lifetime of the scope.
517
517
// More importantly, it serves as an identity map - for a given Zig
518
518
// instance, we map it to the same PersistentObject.
519
+ // The key is the @intFromPtr of the Zig value
519
520
identity_map : std .AutoHashMapUnmanaged (usize , PersistentObject ) = .{},
520
521
522
+ // Similar to the identity map, but used much less frequently. Some
523
+ // web APIs have to manage opaque values. Ideally, they use an
524
+ // JsObject, but the JsObject has no lifetime guarantee beyond the
525
+ // current call. They can call .persist() on their JsObject to get
526
+ // a `*PersistentObject()`. We need to track these to free them.
527
+ // The key is the @intFromPtr of the v8.Object.handle.
528
+ js_object_map : std .AutoHashMapUnmanaged (usize , PersistentObject ) = .{},
529
+
521
530
// When we need to load a resource (i.e. an external script), we call
522
531
// this function to get the source. This is always a reference to the
523
532
// Page's fetchModuleSource, but we use a function pointer
@@ -535,10 +544,20 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
535
544
// no init, started with executor.startScope()
536
545
537
546
fn deinit (self : * Scope ) void {
538
- var it = self .identity_map .valueIterator ();
539
- while (it .next ()) | p | {
540
- p .deinit ();
547
+ {
548
+ var it = self .identity_map .valueIterator ();
549
+ while (it .next ()) | p | {
550
+ p .deinit ();
551
+ }
552
+ }
553
+
554
+ {
555
+ var it = self .js_object_map .valueIterator ();
556
+ while (it .next ()) | p | {
557
+ p .deinit ();
558
+ }
541
559
}
560
+
542
561
for (self .callbacks .items ) | * cb | {
543
562
cb .deinit ();
544
563
}
@@ -871,13 +890,13 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
871
890
scope : * Scope ,
872
891
js_obj : v8.Object ,
873
892
874
- // If a Zig struct wants the Object parameter, it'll declare a
893
+ // If a Zig struct wants the JsObject parameter, it'll declare a
875
894
// function like:
876
- // fn _length(self: *const NodeList, js_obj: Env.Object ) usize
895
+ // fn _length(self: *const NodeList, js_obj: Env.JsObject ) usize
877
896
//
878
897
// When we're trying to call this function, we can't just do
879
- // if (params[i].type.? == Object )
880
- // Because there is _no_ object , there's only an Env.Object , where
898
+ // if (params[i].type.? == JsObject )
899
+ // Because there is _no_ JsObject , there's only an Env.JsObject , where
881
900
// Env is a generic.
882
901
// We could probably figure out a way to do this, but simply checking
883
902
// for this declaration is _a lot_ easier.
@@ -915,6 +934,22 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
915
934
pub fn format (self : JsObject , comptime _ : []const u8 , _ : std.fmt.FormatOptions , writer : anytype ) ! void {
916
935
return writer .writeAll (try self .toString ());
917
936
}
937
+
938
+ pub fn persist (self : JsObject ) ! JsObject {
939
+ var scope = self .scope ;
940
+ const js_obj = self .js_obj ;
941
+ const handle = js_obj .handle ;
942
+
943
+ const gop = try scope .js_object_map .getOrPut (scope .scope_arena , @intFromPtr (handle ));
944
+ if (gop .found_existing == false ) {
945
+ gop .value_ptr .* = PersistentObject .init (scope .isolate , js_obj );
946
+ }
947
+
948
+ return .{
949
+ .scope = scope ,
950
+ .js_obj = gop .value_ptr .castToObject (),
951
+ };
952
+ }
918
953
};
919
954
920
955
// This only exists so that we know whether a function wants the opaque
@@ -1448,6 +1483,11 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
1448
1483
return value .func .toValue ();
1449
1484
}
1450
1485
1486
+ if (T == JsObject ) {
1487
+ // we're returning a v8.Object
1488
+ return value .js_obj .toValue ();
1489
+ }
1490
+
1451
1491
if (s .is_tuple ) {
1452
1492
// return the tuple struct as an array
1453
1493
var js_arr = v8 .Array .init (isolate , @intCast (s .fields .len ));
@@ -1495,7 +1535,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
1495
1535
.error_union = > return zigValueToJs (templates , isolate , context , value catch | err | return err ),
1496
1536
else = > {},
1497
1537
}
1498
- @compileLog ( @typeInfo ( T ));
1538
+
1499
1539
@compileError ("A function returns an unsupported type: " ++ @typeName (T ));
1500
1540
}
1501
1541
// Reverses the mapZigInstanceToJs, making sure that our TaggedAnyOpaque
0 commit comments