177 lines
4.1 KiB
Markdown
177 lines
4.1 KiB
Markdown
# zig interface helper
|
|
|
|
first why does this exist i didnt like having to write `*anyopaque` for all the functions that are in the implemention of an interface so i made wrapper do it for you. This now hides all the nasty polymorphism shenanigans within the interface where it belongs.
|
|
Additionally it also allows you to use your implementation normally rather than having to pass it through the interface first.
|
|
|
|
# using this lib
|
|
|
|
```bash
|
|
$ zig fetch --save git+https://git.sirlilpanda.studio/sirlilpanda/zig-interface-helpers
|
|
```
|
|
|
|
in `build.zig`
|
|
```zig
|
|
|
|
const iface = b.dependency("interface", .{
|
|
.target = target,
|
|
.optimize = optimize,
|
|
});
|
|
|
|
exe.root_module.addImport("interface", interface.module("interface"));
|
|
|
|
```
|
|
|
|
|
|
# how does this lib work
|
|
|
|
This lib basically removes the annoying conversion back to the original type in your implementation and instead does that conversion in a wrapper functions instead. This should now allow you to write more code and less boilerplate.
|
|
|
|
In essence all this lib does is
|
|
```zig
|
|
...
|
|
somefn : *const fn(*anyopaque, u8, []const u8) !?f32
|
|
...
|
|
```
|
|
to using (`VtableFn`)
|
|
```zig
|
|
...
|
|
somefn : *const fn(struct {*anyopaque, u8, []const u8}) !?f32
|
|
...
|
|
```
|
|
|
|
and your implementation functions from
|
|
|
|
```zig
|
|
...
|
|
pub fn area(self : Self, times : f32) f32 {
|
|
return self.h * self.w * times;
|
|
}
|
|
...
|
|
```
|
|
to using (`ToVtableFn`)
|
|
```zig
|
|
pub fn areaWrapper(args : struct {*anyopaque, f32}) f32 {
|
|
const self : orignal_type = @ptrCast(@alignCast(args[0]));
|
|
|
|
return @call(.auto, area, {
|
|
self,
|
|
args[1],
|
|
});
|
|
}
|
|
```
|
|
|
|
|
|
# example
|
|
|
|
```zig
|
|
|
|
const Iface = @import("zig_interface_testing");
|
|
|
|
|
|
// implemention
|
|
const Circle = struct {
|
|
const Self = @This();
|
|
radius: f32,
|
|
|
|
pub fn init(r: f32) Self {
|
|
return Self{
|
|
.radius = r,
|
|
};
|
|
}
|
|
|
|
pub fn perimeter(self: Self) f32 {
|
|
return std.math.pi * self.radius * 2;
|
|
}
|
|
|
|
pub fn area(self: Self) f32 {
|
|
return std.math.pi * self.radius * self.radius;
|
|
}
|
|
|
|
pub fn format(
|
|
self: Self,
|
|
writer: *std.Io.Writer,
|
|
) !void {
|
|
try writer.print("Circle : {}", .{self.radius});
|
|
}
|
|
};
|
|
|
|
// implemention
|
|
const Rect = struct {
|
|
const Self = @This();
|
|
|
|
w: f32,
|
|
h: f32,
|
|
|
|
pub fn init(w: f32, h: f32) Self {
|
|
return Self{
|
|
.w = w,
|
|
.h = h,
|
|
};
|
|
}
|
|
|
|
pub fn perimeter(self: Rect) f32 {
|
|
return self.h * 2 + self.w * 2;
|
|
}
|
|
|
|
pub fn area(self: Self) f32 {
|
|
return self.h * self.w;
|
|
}
|
|
|
|
pub fn format(
|
|
self: Self,
|
|
writer: *std.Io.Writer,
|
|
) !void {
|
|
try writer.print("sqaure : {}, {}", .{ self.h, self.w });
|
|
}
|
|
};
|
|
|
|
// interface
|
|
const Shape = struct {
|
|
const Self = @This();
|
|
data: *anyopaque,
|
|
vtable: *const Vtable,
|
|
|
|
// create your vtable
|
|
const Vtable = struct {
|
|
// convert your vtable functions with Iface.VtableFn
|
|
perimeter_fn: *const Iface.VtableFn(fn (*anyopaque) f32), // -> *const fn (tuple) returnType
|
|
area_fn: *const Iface.VtableFn(fn (*anyopaque) f32),
|
|
format_fn: *const Iface.VtableFn(fn (self: *anyopaque, writer: *std.Io.Writer) anyerror!void),
|
|
};
|
|
|
|
pub fn init(shape: anytype) Self {
|
|
std.debug.print("shape : {*}\n", .{shape});
|
|
const self = Self{
|
|
.data = @ptrCast(shape),
|
|
.vtable = &Vtable{
|
|
// convert your implemation functions to that of the vtable
|
|
.perimeter_fn = Iface.ToVtableFn(@field(@TypeOf(shape.*), "perimeter")),
|
|
.area_fn = Iface.ToVtableFn(@field(@TypeOf(shape.*), "area")),
|
|
.format_fn = Iface.ToVtableFn(@field(@TypeOf(shape.*), "format")),
|
|
},
|
|
};
|
|
|
|
return self;
|
|
}
|
|
|
|
|
|
pub fn perimeter(self: Self) f32 {
|
|
// run them functions
|
|
return self.vtable.perimeter_fn(.{self.data});
|
|
}
|
|
|
|
pub fn area(self: Self) f32 {
|
|
return self.vtable.area_fn(.{self.data});
|
|
}
|
|
|
|
pub fn format(
|
|
self: Self,
|
|
writer: *std.Io.Writer,
|
|
) !void {
|
|
self.vtable.format_fn(.{ self.data, writer }) catch {
|
|
return std.Io.Writer.Error.WriteFailed;
|
|
};
|
|
}
|
|
};
|
|
|
|
``` |