@@ -20,6 +20,8 @@ const std = @import("std");
2020const builtin = @import ("builtin" );
2121const v8 = @import ("v8" );
2222
23+ const SubType = @import ("subtype.zig" ).SubType ;
24+
2325const Allocator = std .mem .Allocator ;
2426const ArenaAllocator = std .heap .ArenaAllocator ;
2527
@@ -72,14 +74,14 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
7274 // that looks like:
7375 //
7476 // const TypeLookup = struct {
75- // comptime cat: usize = 0 ,
76- // comptime owner: usize = 1 ,
77+ // comptime cat: usize = TypeMeta{.index = 0, ...} ,
78+ // comptime owner: usize = TypeMeta{.index = 1, ...} ,
7779 // ...
7880 // }
7981 //
8082 // So to get the template index of `owner`, we can do:
8183 //
82- // const index_id = @field(type_lookup, @typeName(@TypeOf(res));
84+ // const index_id = @field(type_lookup, @typeName(@TypeOf(res)).index ;
8385 //
8486 const TypeLookup = comptime blk : {
8587 var fields : [Types .len ]std.builtin.Type.StructField = undefined ;
@@ -94,13 +96,16 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
9496 @compileError (std .fmt .comptimePrint ("Prototype '{s}' for type '{s} must be a pointer" , .{ @typeName (Struct .prototype ), @typeName (Struct ) }));
9597 }
9698
99+ const subtype : ? SubType =
100+ if (@hasDecl (Struct , "subtype" )) std .meta .stringToEnum (SubType , Struct .subtype ) else null ;
101+
97102 const R = Receiver (@field (types , s .name ));
98103 fields [i ] = .{
99104 .name = @typeName (R ),
100- .type = usize ,
105+ .type = TypeMeta ,
101106 .is_comptime = true ,
102107 .alignment = @alignOf (usize ),
103- .default_value_ptr = @ptrCast ( & i ) ,
108+ .default_value_ptr = & TypeMeta { . index = i , . subtype = subtype } ,
104109 };
105110 }
106111 break :blk @Type (.{ .@"struct" = .{
@@ -135,7 +140,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
135140 if (@hasDecl (Struct , "prototype" )) {
136141 const TI = @typeInfo (Struct .prototype );
137142 const proto_name = @typeName (Receiver (TI .pointer .child ));
138- prototype_index = @field (TYPE_LOOKUP , proto_name );
143+ prototype_index = @field (TYPE_LOOKUP , proto_name ). index ;
139144 }
140145 table [i ] = prototype_index ;
141146 }
@@ -158,7 +163,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
158163 // access to its TunctionTemplate (the thing we need to create an instance
159164 // of it)
160165 // I.e.:
161- // const index = @field(TYPE_LOOKUP, @typeName(type_name))
166+ // const index = @field(TYPE_LOOKUP, @typeName(type_name)).index
162167 // const template = templates[index];
163168 templates : [Types .len ]v8.FunctionTemplate ,
164169
@@ -214,7 +219,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
214219 // Populate our templates lookup. generateClass creates the
215220 // v8.FunctionTemplate, which we store in our env.templates.
216221 // The ordering doesn't matter. What matters is that, given a type
217- // we can get its index via: @field(TYPE_LOOKUP, type_name)
222+ // we can get its index via: @field(TYPE_LOOKUP, type_name).index
218223 const templates = & env .templates ;
219224 inline for (Types , 0.. ) | s , i | {
220225 templates [i ] = env .generateClass (@field (types , s .name ));
@@ -234,7 +239,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
234239 // Just like we said above, given a type, we can get its
235240 // template index.
236241
237- const proto_index = @field (TYPE_LOOKUP , proto_name );
242+ const proto_index = @field (TYPE_LOOKUP , proto_name ). index ;
238243 templates [i ].inherit (templates [proto_index ]);
239244 }
240245 }
@@ -288,7 +293,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
288293 if (@hasDecl (Global , "prototype" )) {
289294 const proto_type = Receiver (@typeInfo (Global .prototype ).pointer .child );
290295 const proto_name = @typeName (proto_type );
291- const proto_index = @field (TYPE_LOOKUP , proto_name );
296+ const proto_index = @field (TYPE_LOOKUP , proto_name ). index ;
292297 globals .inherit (templates [proto_index ]);
293298 }
294299
@@ -309,7 +314,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
309314 @compileError ("Type '" ++ @typeName (Struct ) ++ "' defines an unknown prototype: " ++ proto_name );
310315 }
311316
312- const proto_index = @field (TYPE_LOOKUP , proto_name );
317+ const proto_index = @field (TYPE_LOOKUP , proto_name ). index ;
313318 const proto_obj = templates [proto_index ].getFunction (context ).toObject ();
314319
315320 const self_obj = templates [i ].getFunction (context ).toObject ();
@@ -640,7 +645,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
640645 .one = > {
641646 const type_name = @typeName (ptr .child );
642647 if (@hasField (TypeLookup , type_name )) {
643- const template = templates [@field (TYPE_LOOKUP , type_name )];
648+ const template = templates [@field (TYPE_LOOKUP , type_name ). index ];
644649 const js_obj = try Executor .mapZigInstanceToJs (context , template , value );
645650 return js_obj .toValue ();
646651 }
@@ -676,7 +681,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
676681 .@"struct" = > | s | {
677682 const type_name = @typeName (T );
678683 if (@hasField (TypeLookup , type_name )) {
679- const template = templates [@field (TYPE_LOOKUP , type_name )];
684+ const template = templates [@field (TYPE_LOOKUP , type_name ). index ];
680685 const js_obj = try Executor .mapZigInstanceToJs (context , template , value );
681686 return js_obj .toValue ();
682687 }
@@ -960,10 +965,11 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
960965 // well as any meta data we'll need to use it later.
961966 // See the TaggedAnyOpaque struct for more details.
962967 const tao = try scope_arena .create (TaggedAnyOpaque );
968+ const meta = @field (TYPE_LOOKUP , @typeName (ptr .child ));
963969 tao .* = .{
964970 .ptr = value ,
965- .index = @field ( TYPE_LOOKUP , @typeName ( ptr . child )) ,
966- .sub_type = if ( @hasDecl ( ptr . child , "sub_type" )) ptr . child . sub_type else null ,
971+ .index = meta . index ,
972+ .subtype = meta . subtype ,
967973 .offset = if (@typeInfo (ptr .child ) != .@"opaque" and @hasField (ptr .child , "proto" )) @offsetOf (ptr .child , "proto" ) else -1 ,
968974 };
969975
@@ -1345,7 +1351,7 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
13451351
13461352 const op = js_obj .getInternalField (0 ).castTo (v8 .External ).get ();
13471353 const toa : * TaggedAnyOpaque = @alignCast (@ptrCast (op ));
1348- const expected_type_index = @field (TYPE_LOOKUP , type_name );
1354+ const expected_type_index = @field (TYPE_LOOKUP , type_name ). index ;
13491355
13501356 var type_index = toa .index ;
13511357 if (type_index == expected_type_index ) {
@@ -1379,6 +1385,26 @@ pub fn Env(comptime S: type, comptime types: anytype) type {
13791385 };
13801386}
13811387
1388+ // We'll create a struct with all the types we want to bind to JavaScript. The
1389+ // fields for this struct will be the type names. The values, will be an
1390+ // instance of this struct.
1391+ // const TypeLookup = struct {
1392+ // comptime cat: usize = TypeMeta{.index = 0, subtype = null},
1393+ // comptime owner: usize = TypeMeta{.index = 1, subtype = .array}.
1394+ // ...
1395+ // }
1396+ // This is essentially meta data for each type.
1397+ const TypeMeta = struct {
1398+ // Every type is given a unique index. That index is used to lookup various
1399+ // things, i.e. the prototype chain.
1400+ index : usize ,
1401+
1402+ // We store the type's subtype here, so that when we create an instance of
1403+ // the type, and bind it to JavaScript, we can store the subtype along with
1404+ // the created TaggedAnyOpaque.s
1405+ subtype : ? SubType ,
1406+ };
1407+
13821408fn isEmpty (comptime T : type ) bool {
13831409 return @typeInfo (T ) != .@"opaque" and @sizeOf (T ) == 0 ;
13841410}
@@ -2204,7 +2230,7 @@ const TaggedAnyOpaque = struct {
22042230 // V8 will give us a Value and ask us for the subtype. From the v8.Value we
22052231 // can get a v8.Object, and from the v8.Object, we can get out TaggedAnyOpaque
22062232 // which is where we store the subtype.
2207- sub_type : ? [ * c ] const u8 ,
2233+ subtype : ? SubType ,
22082234};
22092235
22102236fn valueToString (allocator : Allocator , value : v8.Value , isolate : v8.Isolate , context : v8.Context ) ! []u8 {
@@ -2263,7 +2289,7 @@ pub export fn v8_inspector__Client__IMPL__valueSubtype(
22632289 c_value : * const v8.C_Value ,
22642290) callconv (.C ) [* c ]const u8 {
22652291 const external_entry = getTaggedAnyOpaque (.{ .handle = c_value }) orelse return null ;
2266- return if (external_entry .sub_type ) | st | st else null ;
2292+ return if (external_entry .subtype ) | st | @tagName ( st ) else null ;
22672293}
22682294
22692295// Same as valueSubType above, but for the optional description field.
@@ -2280,7 +2306,7 @@ pub export fn v8_inspector__Client__IMPL__descriptionForValueSubtype(
22802306 // We _must_ include a non-null description in order for the subtype value
22812307 // to be included. Besides that, I don't know if the value has any meaning
22822308 const external_entry = getTaggedAnyOpaque (.{ .handle = c_value }) orelse return null ;
2283- return if (external_entry .sub_type == null ) null else "" ;
2309+ return if (external_entry .subtype == null ) null else "" ;
22842310}
22852311
22862312fn getTaggedAnyOpaque (value : v8.Value ) ? * TaggedAnyOpaque {
0 commit comments