|
|
|
|
|
by 2c2c2c
499 days ago
|
|
somethign like this I think. i only dabble in zig/systems stuff so there might be better/more idiomatic ways to write parts const std = @import("std");
// base struct
const Animal = struct {
// points to the derived struct
ctx: *anyopaque,
// points to the vtable of the concrete type
vtable: *const VTable,
// the vtable interface derived struct must implement
const VTable = struct {
make_noise: *const fn (ctx: *anyopaque, loudness: u32) anyerror!void,
};
// call the derived struct's implementation
pub fn make_noise(animal: Animal, loudness: u32) anyerror!void {
return animal.vtable.make_noise(animal.ctx, loudness);
}
};
const Dog = struct {
// extra data
weight: u32,
// implement the interface
const vtable = Animal.VTable{
.make_noise = &make_noise,
};
pub fn make_noise(ctx: *anyopaque, loudness: u32) anyerror!void {
const dog: *Dog = @alignCast(@ptrCast(ctx));
std.debug.print("woof {} {}\n", .{ dog.weight, loudness });
}
// helper to convert to the base struct
pub fn _animal(self: *Dog) Animal {
return Animal{
.ctx = @ptrCast(self),
.vtable = &vtable,
};
}
};
const Cat = struct {
weight: u32,
const vtable = Animal.VTable{
.make_noise = &make_noise,
};
pub fn _animal(self: *Cat) Animal {
return Animal{
.ctx = @ptrCast(self),
.vtable = &vtable,
};
}
pub fn make_noise(ctx: *anyopaque, loudness: u32) anyerror!void {
const cat: *Cat = @alignCast(@ptrCast(ctx));
std.debug.print("meow {} {}\n", .{ cat.weight, loudness });
}
};
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
const alloc = gpa.allocator();
// list of base structs
var animal_list = std.ArrayList(Animal).init(alloc);
defer {
for (animal_list.items) |animal| {
if (animal.vtable == &Dog.vtable) {
const dog: *Dog = @alignCast(@ptrCast(animal.ctx));
alloc.destroy(dog);
} else if (animal.vtable == &Cat.vtable) {
const cat: *Cat = @alignCast(@ptrCast(animal.ctx));
alloc.destroy(cat);
}
}
animal_list.deinit();
}
for (0..20) |i| {
if (i % 2 == 0) {
var dog = try alloc.create(Dog);
dog.* = Dog{ .weight = @intCast(i) };
try animal_list.append(dog._animal());
} else {
var cat = try alloc.create(Cat);
cat.* = Cat{ .weight = @intCast(i) };
try animal_list.append(cat._animal());
}
}
// meows and woofs here
for (animal_list.items) |animal| {
try animal.make_noise(10);
}
}
ive written a couple and still find them mindbendy |
|