Ziglang Memo

#### Interface

##### Pattern 1
```zig
const std = @import("std");

const Animal = union(enum) {
    cat: Cat,
    dog: Dog,

    pub fn talk(self: Animal) void {
        switch (self) {
            inline else => |case| case.talk(),
        }
    }
};

const Cat = struct {
    anger_level: usize,

    pub fn talk(self: Cat) void {
        std.debug.print("[Cat] Meow! (anger Lv {})\n", .{self.anger_level});
    }
};

const Dog = struct {
    name: []const u8,

    pub fn talk(self: Dog) void {
        std.debug.print("[Dog] I'm a {s}\n", .{self.name});
    }
};

pub fn main() !void {
    const cat = Animal{ .cat = .{ .anger_level = 100 } };
    cat.talk();
    const dog = Animal{ .dog = .{ .name = "lilly" } };
    dog.talk();

    const animals = [_]Animal{
        cat,
        dog,
    };

    for (animals) |a| {
        a.talk();
    }
}
```

##### Pattern 2
```zig
const std = @import("std");
const assert = std.debug.assert;

const Animal = struct {
    ptr: *anyopaque,
    vtab: *const VTab,

    const VTab = struct {
        talk: *const fn (ptr: *anyopaque) void,
    };

    pub fn talk(self: Animal) void {
        self.vtab.talk(self.ptr);
    }

    pub fn init(obj: anytype) Animal {
        const Ptr = @TypeOf(obj);
        const PtrInfo = @typeInfo(Ptr);
        assert(PtrInfo == .Pointer); // Must be a pointer
        assert(PtrInfo.Pointer.size == .One); // Must be a single-item pointer
        assert(@typeInfo(PtrInfo.Pointer.child) == .Struct); // Must point to a struct
        const impl = struct {
            fn talk(ptr: *anyopaque) void {
                const self: Ptr = @ptrCast(@alignCast(ptr));
                self.talk();
            }
        };
        return .{
            .ptr = obj,
            .vtab = &.{
                .talk = impl.talk,
            },
        };
    }
};

const Cat = struct {
    anger_level: usize,

    pub fn talk(self: Cat) void {
        std.debug.print("[Cat] Meow! (anger Lv {})\n", .{self.anger_level});
    }
};

const Dog = struct {
    name: []const u8,

    pub fn talk(self: Dog) void {
        std.debug.print("[Dog] I'm a {s}\n", .{self.name});
    }
};

pub fn main() !void {
    var c = Cat{ .anger_level = 100 };
    const cat = Animal.init(&c);
    cat.talk();

    var d = Dog{ .name = "lilly" };
    const dog = Animal.init(&d);
    dog.talk();

    const animals = [_]Animal{
        cat,
        dog,
    };

    for (animals) |a| {
        a.talk();
    }
}
```

##### Pattern 3
```zig
const std = @import("std");
const assert = std.debug.assert;

const Animal = struct {
    ptr: *anyopaque,

    talkFnPtr: *const fn (ptr: *anyopaque) void,

    pub fn init(obj: anytype, comptime talkFn: fn (ptr: @TypeOf(obj)) void) Animal {
        const Ptr = @TypeOf(obj);
        const PtrInfo = @typeInfo(Ptr);
        assert(PtrInfo == .Pointer); // Must be a pointer
        assert(PtrInfo.Pointer.size == .One); // Must be a single-item pointer
        assert(@typeInfo(PtrInfo.Pointer.child) == .Struct); // Must point to a struct
        const impl = struct {
            fn talk(ptr: *anyopaque) void {
                const self: Ptr = @ptrCast(@alignCast(ptr));
                talkFn(self);
            }
        };
        return .{
            .ptr = obj,
            .talkFnPtr = impl.talk,
        };
    }

    pub fn talk(self: Animal) void {
        self.talkFnPtr(self.ptr);
    }
};

const Cat = struct {
    anger_level: usize,

    pub fn talk(self: *Cat) void {
        std.debug.print("[Cat] Meow! (anger Lv {})\n", .{self.anger_level});
    }
};

const Dog = struct {
    name: []const u8,

    pub fn talk(self: *Dog) void {
        std.debug.print("[Dog] I'm a {s}\n", .{self.name});
    }
};

pub fn main() !void {
    var c = Cat{ .anger_level = 100 };
    const cat = Animal.init(&c, Cat.talk);
    cat.talk();

    var d = Dog{ .name = "lilly" };
    const dog = Animal.init(&d, Dog.talk);
    dog.talk();

    const animals = [_]Animal{
        cat,
        dog,
    };

    for (animals) |a| {
        a.talk();
    }
}
```

##### Pattern 4
```zig
const std = @import("std");
const assert = std.debug.assert;

const Animal = struct {
    talkFn: *const fn (ptr: *Animal) void,

    pub fn talk(self: *Animal) void {
        self.talkFn(self);
    }
};

const Cat = struct {
    anger_level: usize,
    parent: Animal,

    pub fn init(anger_level: usize) Cat {
        const impl = struct {
            pub fn talk(ptr: *Animal) void {
                const self: *Cat = @fieldParentPtr("parent", ptr);
                self.talk();
            }
        };
        return .{
            .anger_level = anger_level,
            .parent = .{ .talkFn = impl.talk },
        };
    }

    pub fn talk(self: *Cat) void {
        std.debug.print("[Cat] Meow! (anger Lv {})\n", .{self.anger_level});
    }
};

const Dog = struct {
    name: []const u8,
    parent: Animal,

    pub fn init(name: []const u8) Dog {
        const impl = struct {
            pub fn talk(ptr: *Animal) void {
                const self: *Dog = @fieldParentPtr("parent", ptr);
                self.talk();
            }
        };
        return .{
            .name = name,
            .parent = .{ .talkFn = impl.talk },
        };
    }

    pub fn talk(self: *Dog) void {
        std.debug.print("[Dog] I'm a {s}\n", .{self.name});
    }
};

pub fn main() !void {
    var cat = Cat.init(100);
    cat.talk();

    var dog = Dog.init("lilly");
    dog.talk();

    const animals = [_]*Animal{
        &cat.parent,
        &dog.parent,
    };

    // const animals = [_]*Animal{
    //     @constCast(&Cat.init(100).parent),
    //     @constCast(&Dog.init("lilly").parent),
    // };

    for (animals) |a| {
        a.talk();
    }
}
```

##### Pattern 5
```zig
const std = @import("std");

const Animal = struct {
    pub fn talk(self: anytype) void {
        self.talk();
    }
};

const Cat = struct {
    anger_level: usize,

    pub fn talk(self: Cat) void {
        std.debug.print("[Cat] Meow! (anger Lv {})\n", .{self.anger_level});
    }
};

const Dog = struct {
    name: []const u8,

    pub fn talk(self: Dog) void {
        std.debug.print("[Dog] I'm a {s}\n", .{self.name});
    }
};

const Panda = struct {
    // error: no field or member function named 'talk' in 't5.Panda'
    //
    // pub fn talk(_: Panda) void {
    //     std.debug.print("Hahaha!\n", .{});
    // }
};

pub fn main() !void {
    const cat = Cat{ .anger_level = 100 };
    Animal.talk(cat);
    const dog = Dog{ .name = "lilly" };
    Animal.talk(dog);
    const panda = Panda{};
    Animal.talk(panda);
}
```
- [Code study: interface idioms/patterns in zig standard libraries](https://zig.news/yglcode/code-study-interface-idiomspatterns-in-zig-standard-libraries-4lkj)

#### 無名関数の色々を取得
```zig
fn foo(options: anytype) void {
    inline for (@typeInfo(@TypeOf(options)).Struct.fields) |field| {
        std.debug.print("{s}: {} {}\n", .{ field.name, @field(options, field.name), field.type });
    }
}

pub fn main() !void {
    const a: u8, const b: u8 = .{ 0, 1 };
    // const a, const b = .{ @as(u8, 0), @as(u8, 1) };
    foo(.{ .a = a, .b = b });
}
```
- @ typeInfo(type)は[std.builtin.Type](https://ziglang.org/documentation/master/std/#std.builtin.Type)を返す.

#### Pointer
```zig
test "*const T and *T" {
    // immutable
    const x: i32 = 1234;
    const x_ptr = &x;
    try expect(@TypeOf(x_ptr) == *const i32);
    // Error
    // x_ptr.* = 5678;
    try expect(x_ptr.* == 1234);

    // mutable
    var y: i32 = 1234;
    const y_ptr = &y;
    try expect(@TypeOf(y_ptr) == *i32);
    // Ok
    y_ptr.* = 5678;
    try expect(y_ptr.* == 5678);
}

test "pointer array access" {
    var array = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    const ptr = &array[2];
    try expect(@TypeOf(ptr) == *u8);

    try expect(array[2] == 3);
    ptr.* += 1;
    try expect(array[2] == 4);

    // Error
    // ptr[1] = 255;

    // Ok
    const ptr2 = @ptrFromInt(*u8, @intFromPtr(ptr) + @sizeOf(u8));
    ptr2.* = 255;
    try expect(array[3] == 255);
}

test "*const [N]T and *[N]T" {
    // immutable
    const x = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    const x_ptr = &x;
    // Error
    // ptr[0] = 255;
    try expect(@TypeOf(x_ptr) == *const [10]u8);
    try expect(x[0] == 1);

    // mutable
    var y = [_]u8{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
    const y_ptr = &y;
    // Ok
    y_ptr[0] = 255;
    try expect(@TypeOf(y_ptr) == *[10]u8);
    try expect(y[0] == 255);
}
```
- [Type/pointer cheatsheet](https://zig.news/toxi/typepointer-cheatsheet-3ne2)

#### 部分的にzig fmtを無効にする
```zig
// zig fmt: off
            var arr = [_]u8{ 1, 2 };
// zig fmt: on
var arr1 = [_]u8{ 1, 2 };
```

#### Overflow
```zig
const std = @import("std");

test "@addWithOverflow" {
    const result = @addWithOverflow(@as(u8, std.math.maxInt(u8)), @as(u8, 10));
    try std.testing.expectEqual(result, .{ 9, 1 });
}

test "std.math.add" {
    const result = std.math.add(u8, std.math.maxInt(u8), 10) catch std.math.maxInt(u8);
    try std.testing.expect(result == 255);
}
```