about summary refs log tree commit diff
path: root/lang/zig/structs.zig
diff options
context:
space:
mode:
Diffstat (limited to 'lang/zig/structs.zig')
-rw-r--r--lang/zig/structs.zig133
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);
+}