diff options
Diffstat (limited to 'lang/zig/structs.zig')
-rw-r--r-- | lang/zig/structs.zig | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/lang/zig/structs.zig b/lang/zig/structs.zig new file mode 100644 index 0000000..d90f4ff --- /dev/null +++ b/lang/zig/structs.zig @@ -0,0 +1,133 @@ +// Declare a struct. +// Zig gives no guarantees about the order of fields and the size of +// the struct but the fields are guaranteed to be ABI-aligned. +const Point = struct { + x: f32, + y: f32, +}; + +// Maybe we want to pass it to OpenGL so we want to be particular about +// how the bytes are arranged. +const Point2 = packed struct { + x: f32, + y: f32, +}; + +// Declare an instance of a struct. +const p = Point { + .x = 0.12, + .y = 0.34, +}; + +// Maybe we're not ready to fill out some of the fields. +var p2 = Point { + .x = 0.12, + .y = undefined, +}; + +// Structs can have methods +// Struct methods are not special, they are only namespaced +// functions that you can call with dot syntax. +const Vec3 = struct { + x: f32, + y: f32, + z: f32, + + pub fn init(x: f32, y: f32, z: f32) Vec3 { + return Vec3 { + .x = x, + .y = y, + .z = z, + }; + } + + pub fn dot(self: Vec3, other: Vec3) f32 { + return self.x * other.x + self.y * other.y + self.z * other.z; + } +}; + +const expect = @import("std").testing.expect; +test "dot product" { + const v1 = Vec3.init(1.0, 0.0, 0.0); + const v2 = Vec3.init(0.0, 1.0, 0.0); + expect(v1.dot(v2) == 0.0); + + // Other than being available to call with dot syntax, struct methods are + // not special. You can reference them as any other declaration inside + // the struct: + expect(Vec3.dot(v1, v2) == 0.0); +} + +// Structs can have global declarations. +// Structs can have 0 fields. +const Empty = struct { + pub const PI = 3.14; +}; +test "struct namespaced variable" { + expect(Empty.PI == 3.14); + expect(@sizeOf(Empty) == 0); + + // you can still instantiate an empty struct + const does_nothing = Empty {}; +} + +// struct field order is determined by the compiler for optimal performance. +// however, you can still calculate a struct base pointer given a field pointer: +fn setYBasedOnX(x: *f32, y: f32) void { + const point = @fieldParentPtr(Point, "x", x); + point.y = y; +} +test "field parent pointer" { + var point = Point { + .x = 0.1234, + .y = 0.5678, + }; + setYBasedOnX(&point.x, 0.9); + expect(point.y == 0.9); +} + +// You can return a struct from a function. +// This is how we do generics in Zig: +fn LinkedList(comptime T: type) type { + return struct { + pub const Node = struct { + prev: ?*Node, + next: ?*Node, + data: T, + }; + + first: ?*Node, + last: ?*Node, + len: usize, + }; +} + +test "linked list" { + // Functions called at compile-time are memoized. + // This means you can do this: + expect(LinkedList(i32) == LinkedList(i32)); + + var list = LinkedList(i32) { + .first = null, + .last = null, + .len = 0, + }; + expect(list.len == 0); + + // Since types are first class values you can instantiate the type + // by assigning it to a variable: + const ListOfInts = LinkedList(i32); + expect(ListOfInts == LinkedList(i32)); + + var node = ListOfInts.Node { + .prev = null, + .next = null, + .data = 1234, + }; + var list2 = LinkedList(i32) { + .first = &node, + .last = &node, + .len = 1, + }; + expect(list2.first.?.data == 1234); +} |