intrusive-interface.zig

Working version(s):
0.13.00.14.1

Failing version(s):
0.15.20.16.0-dev.2637+6a9510c0e

Code

const std = @import("std");

const IntrusiveInterface = struct {
    behavior1Fn: *const fn (ptr: *IntrusiveInterface) u32,
    behavior2Fn: *const fn (ptr: *IntrusiveInterface, arg: u32) u32,

    pub fn behavior1(self: *IntrusiveInterface) u32 {
        return self.behavior1Fn(self);
    }

    pub fn behavior2(self: *IntrusiveInterface, arg: u32) u32 {
        return self.behavior2Fn(self, arg);
    }
};

const ConcreteType = struct {
    interface: IntrusiveInterface,
    data: u32,

    fn behavior1Fn(ptr: *IntrusiveInterface) u32 {
        const self: *ConcreteType = @fieldParentPtr("interface", ptr);
        return self.data;
    }

    fn behavior2Fn(ptr: *IntrusiveInterface, arg: u32) u32 {
        const self: *ConcreteType = @fieldParentPtr("interface", ptr);
        self.data += arg;
        return self.data;
    }
};

test {
    var crew_mate = ConcreteType{
        .interface = .{
            .behavior1Fn = ConcreteType.behavior1Fn,
            .behavior2Fn = ConcreteType.behavior2Fn,
        },
        .data = 10,
    };
    var among_us: *IntrusiveInterface = &crew_mate.interface;
    try std.testing.expectEqual(10, among_us.behavior1());
    try std.testing.expectEqual(15, among_us.behavior2(5));
    try std.testing.expectEqual(15, crew_mate.data);
}