@@ -259,63 +259,68 @@ fn getFunctionFromImpl(comptime name: []const u8, comptime FnT: type, comptime I
259
259
260
260
if (args .len == 0 ) {
261
261
return null ;
262
+ // @TODO
262
263
}
263
264
264
- const arg0_type = args [0 ].arg_type .? ;
265
- if (arg0_type != ImplT and arg0_type != * ImplT and arg0_type != * const ImplT ) {
266
- return null ;
267
- }
265
+ if (args .len > 0 ) {
266
+ const arg0_type = args [0 ].arg_type .? ;
267
+ const is_method = arg0_type == ImplT or arg0_type == * ImplT or arg0_type == * const ImplT ;
268
268
269
- const candidate_cc = @typeInfo (fn_decl .fn_type ).Fn .calling_convention ;
270
- switch (candidate_cc ) {
271
- .Async , .Unspecified = > {},
272
- else = > return null ,
273
- }
269
+ const candidate_cc = @typeInfo (fn_decl .fn_type ).Fn .calling_convention ;
270
+ switch (candidate_cc ) {
271
+ .Async , .Unspecified = > {},
272
+ else = > return null ,
273
+ }
274
274
275
- const Return = @typeInfo (FnT ).Fn .return_type orelse noreturn ;
276
- const CurrSelfType = @typeInfo (FnT ).Fn .args [0 ].arg_type .? ;
275
+ const Return = @typeInfo (FnT ).Fn .return_type orelse noreturn ;
276
+ const CurrSelfType = @typeInfo (FnT ).Fn .args [0 ].arg_type .? ;
277
277
278
- const call_type : GenCallType = switch (our_cc ) {
279
- .Async = > if (candidate_cc == .Async ) .BothAsync else .AsyncCallsBlocking ,
280
- .Unspecified = > if (candidate_cc == .Unspecified ) .BothBlocking else .BlockingCallsAsync ,
281
- else = > unreachable ,
282
- };
278
+ const call_type : GenCallType = switch (our_cc ) {
279
+ .Async = > if (candidate_cc == .Async ) .BothAsync else .AsyncCallsBlocking ,
280
+ .Unspecified = > if (candidate_cc == .Unspecified ) .BothBlocking else .BlockingCallsAsync ,
281
+ else = > unreachable ,
282
+ };
283
283
284
- // TODO: Make this less hacky somehow?
285
- // We need some new feature to do so unfortunately.
286
- return switch (args .len ) {
287
- 1 = > struct {
288
- fn impl (self_ptr : CurrSelfType ) callconv (our_cc ) Return {
289
- return @call (.{ .modifier = .always_inline }, makeCall , .{ name , CurrSelfType , Return , ImplT , call_type , self_ptr , .{} });
290
- }
291
- }.impl ,
292
- 2 = > struct {
293
- fn impl (self_ptr : CurrSelfType , arg : args [1 ].arg_type .? ) callconv (our_cc ) Return {
294
- return @call (.{ .modifier = .always_inline }, makeCall , .{ name , CurrSelfType , Return , ImplT , call_type , self_ptr , .{arg } });
295
- }
296
- }.impl ,
297
- 3 = > struct {
298
- fn impl (self_ptr : CurrSelfType , arg1 : args [1 ].arg_type .? , arg2 : args [2 ].arg_type .? ) callconv (our_cc ) Return {
299
- return @call (.{ .modifier = .always_inline }, makeCall , .{ name , CurrSelfType , Return , ImplT , call_type , self_ptr , .{ arg1 , arg2 } });
300
- }
301
- }.impl ,
302
- 4 = > struct {
303
- fn impl (self_ptr : CurrSelfType , arg1 : args [1 ].arg_type .? , arg2 : args [2 ].arg_type .? , arg3 : args [3 ].arg_type .? ) callconv (our_cc ) Return {
304
- return @call (.{ .modifier = .always_inline }, makeCall , .{ name , CurrSelfType , Return , ImplT , call_type , self_ptr , .{ arg1 , arg2 , arg3 } });
305
- }
306
- }.impl ,
307
- 5 = > struct {
308
- fn impl (self_ptr : CurrSelfType , arg1 : args [1 ].arg_type .? , arg2 : args [2 ].arg_type .? , arg3 : args [3 ].arg_type .? , arg4 : args [4 ].arg_type .? ) callconv (our_cc ) Return {
309
- return @call (.{ .modifier = .always_inline }, makeCall , .{ name , CurrSelfType , Return , ImplT , call_type , self_ptr , .{ arg1 , arg2 , arg3 , arg4 } });
310
- }
311
- }.impl ,
312
- 6 = > struct {
313
- fn impl (self_ptr : CurrSelfType , arg1 : args [1 ].arg_type .? , arg2 : args [2 ].arg_type .? , arg3 : args [3 ].arg_type .? , arg4 : args [4 ].arg_type .? , arg5 : args [5 ].arg_type .? ) callconv (our_cc ) Return {
314
- return @call (.{ .modifier = .always_inline }, makeCall , .{ name , CurrSelfType , Return , ImplT , call_type , self_ptr , .{ arg1 , arg2 , arg3 , arg4 , arg5 } });
315
- }
316
- }.impl ,
317
- else = > @compileError ("Unsupported number of arguments, please provide a manually written vtable." ),
318
- };
284
+ if (! is_method ) {
285
+ return @field (ImplT , name );
286
+ }
287
+
288
+ // TODO: Make this less hacky somehow?
289
+ // We need some new feature to do so unfortunately.
290
+ return switch (args .len ) {
291
+ 1 = > struct {
292
+ fn impl (self_ptr : CurrSelfType ) callconv (our_cc ) Return {
293
+ return @call (.{ .modifier = .always_inline }, makeCall , .{ name , CurrSelfType , Return , ImplT , call_type , self_ptr , .{} });
294
+ }
295
+ }.impl ,
296
+ 2 = > struct {
297
+ fn impl (self_ptr : CurrSelfType , arg : args [1 ].arg_type .? ) callconv (our_cc ) Return {
298
+ return @call (.{ .modifier = .always_inline }, makeCall , .{ name , CurrSelfType , Return , ImplT , call_type , self_ptr , .{arg } });
299
+ }
300
+ }.impl ,
301
+ 3 = > struct {
302
+ fn impl (self_ptr : CurrSelfType , arg1 : args [1 ].arg_type .? , arg2 : args [2 ].arg_type .? ) callconv (our_cc ) Return {
303
+ return @call (.{ .modifier = .always_inline }, makeCall , .{ name , CurrSelfType , Return , ImplT , call_type , self_ptr , .{ arg1 , arg2 } });
304
+ }
305
+ }.impl ,
306
+ 4 = > struct {
307
+ fn impl (self_ptr : CurrSelfType , arg1 : args [1 ].arg_type .? , arg2 : args [2 ].arg_type .? , arg3 : args [3 ].arg_type .? ) callconv (our_cc ) Return {
308
+ return @call (.{ .modifier = .always_inline }, makeCall , .{ name , CurrSelfType , Return , ImplT , call_type , self_ptr , .{ arg1 , arg2 , arg3 } });
309
+ }
310
+ }.impl ,
311
+ 5 = > struct {
312
+ fn impl (self_ptr : CurrSelfType , arg1 : args [1 ].arg_type .? , arg2 : args [2 ].arg_type .? , arg3 : args [3 ].arg_type .? , arg4 : args [4 ].arg_type .? ) callconv (our_cc ) Return {
313
+ return @call (.{ .modifier = .always_inline }, makeCall , .{ name , CurrSelfType , Return , ImplT , call_type , self_ptr , .{ arg1 , arg2 , arg3 , arg4 } });
314
+ }
315
+ }.impl ,
316
+ 6 = > struct {
317
+ fn impl (self_ptr : CurrSelfType , arg1 : args [1 ].arg_type .? , arg2 : args [2 ].arg_type .? , arg3 : args [3 ].arg_type .? , arg4 : args [4 ].arg_type .? , arg5 : args [5 ].arg_type .? ) callconv (our_cc ) Return {
318
+ return @call (.{ .modifier = .always_inline }, makeCall , .{ name , CurrSelfType , Return , ImplT , call_type , self_ptr , .{ arg1 , arg2 , arg3 , arg4 , arg5 } });
319
+ }
320
+ }.impl ,
321
+ else = > @compileError ("Unsupported number of arguments, please provide a manually written vtable." ),
322
+ };
323
+ }
319
324
},
320
325
else = > return null ,
321
326
}
@@ -384,23 +389,19 @@ fn checkVtableType(comptime VTableT: type) void {
384
389
.Unspecified , .Async = > {},
385
390
else = > @compileError ("Virtual function's '" ++ field .name ++ "' calling convention is not default or async." ),
386
391
}
387
-
388
- if (type_info .Fn .args .len == 0 ) {
389
- @compileError ("Virtual function '" ++ field .name ++ "' must have at least one argument." );
390
- }
391
-
392
- const arg_type = type_info .Fn .args [0 ].arg_type .? ;
393
- if (arg_type != * SelfType and arg_type != * const SelfType ) {
394
- @compileError ("Virtual function's '" ++ field .name ++ "' first argument must be *SelfType or *const SelfType" );
395
- }
396
392
}
397
393
}
398
394
399
- fn vtableHasMethod (comptime VTableT : type , comptime name : []const u8 , is_optional : * bool , is_async : * bool ) bool {
395
+ fn vtableHasMethod (comptime VTableT : type , comptime name : []const u8 , is_optional : * bool , is_async : * bool , is_method : * bool ) bool {
400
396
for (std .meta .fields (VTableT )) | field | {
401
397
if (std .mem .eql (u8 , name , field .name )) {
402
398
is_optional .* = trait .is (.Optional )(field .field_type );
403
- is_async .* = @typeInfo (if (is_optional .* ) std .meta .Child (field .field_type ) else field .field_type ).Fn .calling_convention == .Async ;
399
+ const fn_typeinfo = @typeInfo (if (is_optional .* ) std .meta .Child (field .field_type ) else field .field_type ).Fn ;
400
+ is_async .* = fn_typeinfo .calling_convention == .Async ;
401
+ is_method .* = fn_typeinfo .args .len > 0 and blk : {
402
+ const first_arg_type = fn_typeinfo .args [0 ].arg_type .? ;
403
+ break :blk first_arg_type == * SelfType or first_arg_type == * const SelfType ;
404
+ };
404
405
return true ;
405
406
}
406
407
}
@@ -450,29 +451,39 @@ pub fn Interface(comptime VTableT: type, comptime StorageT: type) type {
450
451
pub fn initWithVTable (vtable_ptr : * const VTableT , args : anytype ) ! Self {
451
452
return .{
452
453
.vtable_ptr = vtable_ptr ,
453
- .storage = try StorageT . init (args ),
454
+ .storage = try init (args ),
454
455
};
455
456
}
456
457
457
458
pub fn call (self : anytype , comptime name : []const u8 , args : anytype ) VTableReturnType (VTableT , name ) {
458
459
comptime var is_optional = true ;
459
460
comptime var is_async = true ;
460
- comptime assert (vtableHasMethod (VTableT , name , & is_optional , & is_async ));
461
+ comptime var is_method = true ;
462
+ comptime assert (vtableHasMethod (VTableT , name , & is_optional , & is_async , & is_method ));
461
463
462
464
const fn_ptr = if (is_optional ) blk : {
463
465
const val = @field (self .vtable_ptr , name );
464
466
if (val ) | v | break :blk v ;
465
467
return null ;
466
468
} else @field (self .vtable_ptr , name );
467
469
468
- const self_ptr = self .storage .getSelfPtr ();
469
- const new_args = .{self_ptr };
470
+ if (is_method ) {
471
+ const self_ptr = self .storage .getSelfPtr ();
472
+ const new_args = .{self_ptr };
470
473
471
- if (! is_async ) {
472
- return @call (.{}, fn_ptr , new_args ++ args );
474
+ if (! is_async ) {
475
+ return @call (.{}, fn_ptr , new_args ++ args );
476
+ } else {
477
+ var stack_frame : [stack_size ]u8 align (std .Target .stack_align ) = undefined ;
478
+ return await @asyncCall (& stack_frame , {}, fn_ptr , new_args ++ args );
479
+ }
473
480
} else {
474
- var stack_frame : [stack_size ]u8 align (std .Target .stack_align ) = undefined ;
475
- return await @asyncCall (& stack_frame , {}, fn_ptr , new_args ++ args );
481
+ if (! is_async ) {
482
+ return @call (.{}, fn_ptr , args );
483
+ } else {
484
+ var stack_frame : [stack_size ]u8 align (std .Target .stack_align ) = undefined ;
485
+ return await @asyncCall (& stack_frame , {}, fn_ptr , args );
486
+ }
476
487
}
477
488
}
478
489
0 commit comments