Provides a mixin and type which enables simple definitions of virtual types with a dynamic dispatch interface.
To create a virtual type, you must create a struct which:
- declares:
pub usingnamespace virtual(access, @This());
- has a single field:
vtable: Vtable(access, @This()),
- and implements the interface for a generic type as a pub fn named
iface
pub fn iface(T: type) type { return struct { pub inline fn doSomething(self: *T) void { return self.vtable.draw(self.vtable.__ptr__, data); } } }
To use a virtual type, you must:
- Create a type which implements the interface
const MyImpl = struct { pub fn doSomething(self: @This()) void { } }
- Init the virtual type with a pointer to your implementation type
var my_impl: MyImpl = .{}; var my_virt: MyVirt.init(&my_impl); my_virt.doSomething();
/// A type which has function `doSomething(i32) void` and `doSomethingAndReturn(f32) i32`
fn SomethingDoer(access: Access) type {
return struct {
pub usingnamespace virtual(access, @This());
vtable: Vtable(access, @This()),
pub fn iface(T: type) type {
return struct {
pub inline fn doSomethingVar(self: *const T, value: i32) void {
return self.vtable.get(self.vtable.__ptr__, value);
}
pub inline fn doSomethingConst(self: *T, value: f32) i32 {
return self.vtable.set(self.vtable.__ptr__, value);
}
};
}
};
}
const ExampleDoer = struct {
value: i32,
pub doSomethingVar(self: *@This(), value: i32) void {
self.value = value;
}
pub doSomethingConst(self: * const @This(), value: f32) i32 {
return @intFromFloat(value) + self.value;
}
}
fn main() void {
// declare the virtuals
var something_doer: SomethingDoer(.variable) = undefined;
var something_doer_const: SomethingDoer(.constant) = undefined;
// declare the implementations
var example_doer = ExampleDoer{.value = 0};
const example_doer_const = ExampleDoer{.value = 0};
// use var impl with var virtual
something_doer = SomethingDoer(.variable).init(example_doer); // works
something_doer.doSomethingVar(12); // works
_ = something_doer.doSomethingConst(12.0); // works
// use const impl with const virtual
something_doer_const = SomethingDoer(.constant).init(example_doer_const); // works
something_doer_const.doSomethingVar(12); // does not work! attempt to modify const value
something_doer_const.doSomethingConst(12); // works!
// use const impl with var virtual
something_doer = SomethingDoer(.variable).init(example_doer_const); // does not work! attempt to set variable virtual with const pointer
// use var impl with const virtual is same as const with const
}