Skip to content

Commit

Permalink
fix bug when finding default method
Browse files Browse the repository at this point in the history
  • Loading branch information
zhuyadong committed Sep 20, 2024
1 parent 57058b7 commit 67db992
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 15 deletions.
9 changes: 4 additions & 5 deletions README.CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,11 @@ try t.expectEqualStrings(zoop.vcall(phuman, IName.getName, .{}), "override");
`vcall`的性能说明:
`vcall`会在能使用`cast`的情况下使用`cast`,否则使用`as`

## 调试用接口 `zoop.IFormat`
`zoop.IFormat`能方便通过 `std.fmt``format(...)`机制来输出对象的字符串形式内容。
## 调试用接口 `IObject.formatAny`
`zoop.IObject`能方便通过 `std.fmt``format(...)`机制来输出对象的字符串形式内容。
```zig
// 定义一个实现 `zoop.IFormat`的类
// 定义一个实现 `zoop.IObject.formatAny`的类
pub const SomeClass = struct {
pub const extends = .{zoop.IFormat};
name:[]const u8 align(zoop.alignment) = "some";
pub fn formatAny(self: *SomeClass, writer: std.io.AnyWriter) anyerror!void {
Expand All @@ -284,6 +283,6 @@ pub const SomeClass = struct {
// 下面代码就能输出 `SomeClass.formatAny` 的内容
const psome = try zoop.new(t.allocator, SomeClass, null);
std.debug.print("{}\n", .{zoop.cast(psome, zoop.IFormat)});
std.debug.print("{}\n", .{zoop.cast(psome, zoop.IObject)});
// output: SomeClass.name = some
```
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,12 +281,11 @@ try t.expectEqualStrings(zoop.vcall(phuman, IName.getName, .{}), "override");
Performance notes for `vcall`:
`vcall` will use `cast` when possible, and `as` otherwise

## Interface `zoop.IFormat` for print
`zoop.IFormat` can conveniently output the string content of the object through the `format(...)` mechanism of `std.fmt`.
## `zoop.IObject.formatAny` for print
`zoop.IObject` can conveniently output the string content of the object through the `format(...)` mechanism of `std.fmt`.
```zig
// define a class that implemented `zoop.IFormat`
// define a class that implemented `zoop.IObject.formatAny`
pub const SomeClass = struct {
pub const extends = .{zoop.IFormat};
name:[]const u8 align(zoop.alignment) = "some";
pub fn formatAny(self: *SomeClass, writer: std.io.AnyWriter) anyerror!void {
Expand All @@ -296,6 +295,6 @@ pub const SomeClass = struct {
// print string from `SomeClass.formatAny`
const psome = try zoop.new(t.allocator, SomeClass, null);
std.debug.print("{}\n", .{zoop.cast(psome, zoop.IFormat)});
std.debug.print("{}\n", .{zoop.cast(psome, zoop.IObject)});
// output: SomeClass.name = some
```
34 changes: 29 additions & 5 deletions src/zoop.zig
Original file line number Diff line number Diff line change
Expand Up @@ -751,17 +751,41 @@ fn RealType(comptime T: type) type {

fn DefaultMethodType(comptime T: type, comptime I: type, comptime name: []const u8) type {
comptime {
if (@hasDecl(I, "Default")) {
const def = I.Default(T);
if (@hasDecl(def, name)) {
return @TypeOf(@field(def, name));
const ifaces = interfaces(I);
var all = tupleInit(.{});
for (ifaces.items) |iface| {
if (@hasDecl(iface, "Default")) {
const def = iface.Default(T);
if (@hasDecl(def, name)) {
all = tupleAppend(all, iface);
}
}
}
switch (all.items.len) {
0 => {},
1 => return @TypeOf(@field(all.items[0].Default(T), name)),
else => @compileError(compfmt("multi default method '{s}' found in: {}", .{ name, all.items })),
}

return void;
}
}

fn defaultMethod(comptime T: type, comptime I: type, comptime name: []const u8) DefaultMethodType(T, I, name) {
comptime {
const ifaces = interfaces(I);
for (ifaces.items) |iface| {
if (@hasDecl(iface, "Default")) {
const def = iface.Default(T);
if (@hasDecl(def, name)) {
return @field(def, name);
}
}
}
unreachable;
}
}

fn MethodType(comptime T: type, comptime name: []const u8) type {
comptime {
var Cur = if (isKlassType(T)) T.Class else T;
Expand Down Expand Up @@ -1091,7 +1115,7 @@ fn makeVtable(comptime T: type, comptime I: type) *anyopaque {
@field(val, field.name) = @ptrCast(&getMethod(T, field.name));
} else if (DefaultMethodType(T, I, field.name) != void) {
checkInterface(I);
@field(val, field.name) = &@field(I.Default(T), field.name);
@field(val, field.name) = @ptrCast(&defaultMethod(T, I, field.name));
} else {
@compileError(compfmt("{s} must implement method '{s}: {}'", .{ @typeName(T), field.name, field.type }));
}
Expand Down

0 comments on commit 67db992

Please sign in to comment.