const std = @import("std"); const builtin = @import("builtin"); const native_endian = builtin.target.cpu.arch.endian(); const expect = std.testing.expect; const expectEqual = std.testing.expectEqual; const expectEqualSlices = std.testing.expectEqualSlices; const maxInt = std.math.maxInt; const Node = struct { val: Val, next: *Node, }; const Val = struct { x: i32, }; test "struct point to self" { var root: Node = undefined; root.val.x = 1; var node: Node = undefined; node.next = &root; node.val.x = 2; root.next = &node; try expect(node.next.next.next.val.x == 1); } test "void struct fields" { const foo = VoidStructFieldsFoo{ .a = void{}, .b = 1, .c = void{}, }; try expect(foo.b == 1); try expect(@sizeOf(VoidStructFieldsFoo) == 4); } const VoidStructFieldsFoo = struct { a: void, b: i32, c: void, }; test "return empty struct from fn" { _ = testReturnEmptyStructFromFn(); } const EmptyStruct2 = struct {}; fn testReturnEmptyStructFromFn() EmptyStruct2 { return EmptyStruct2{}; } test "pass slice of empty struct to fn" { try expect(testPassSliceOfEmptyStructToFn(&[_]EmptyStruct2{EmptyStruct2{}}) == 1); } fn testPassSliceOfEmptyStructToFn(slice: []const EmptyStruct2) usize { return slice.len; } test "self-referencing struct via array member" { const T = struct { children: [1]*@This(), }; var x: T = undefined; x = T{ .children = .{&x} }; try expect(x.children[0] == &x); } test "empty struct method call" { const es = EmptyStruct{}; try expect(es.method() == 1234); } const EmptyStruct = struct { fn method(es: *const EmptyStruct) i32 { _ = es; return 1234; } }; test "align 1 field before self referential align 8 field as slice return type" { const result = alloc(Expr); try expect(result.len == 0); } const Expr = union(enum) { Literal: u8, Question: *Expr, }; fn alloc(comptime T: type) []T { return &[_]T{}; } const APackedStruct = packed struct { x: u8, y: u8, }; test "packed struct" { var foo = APackedStruct{ .x = 1, .y = 2, }; foo.y += 1; const four = foo.x + foo.y; try expect(four == 4); } const Foo24Bits = packed struct { field: u24, }; const Foo96Bits = packed struct { a: u24, b: u24, c: u24, d: u24, }; test "packed struct 24bits" { comptime { try expect(@sizeOf(Foo24Bits) == 4); if (@sizeOf(usize) == 4) { try expect(@sizeOf(Foo96Bits) == 12); } else { try expect(@sizeOf(Foo96Bits) == 16); } } var value = Foo96Bits{ .a = 0, .b = 0, .c = 0, .d = 0, }; value.a += 1; try expect(value.a == 1); try expect(value.b == 0); try expect(value.c == 0); try expect(value.d == 0); value.b += 1; try expect(value.a == 1); try expect(value.b == 1); try expect(value.c == 0); try expect(value.d == 0); value.c += 1; try expect(value.a == 1); try expect(value.b == 1); try expect(value.c == 1); try expect(value.d == 0); value.d += 1; try expect(value.a == 1); try expect(value.b == 1); try expect(value.c == 1); try expect(value.d == 1); } test "runtime struct initialization of bitfield" { const s1 = Nibbles{ .x = x1, .y = x1, }; const s2 = Nibbles{ .x = @intCast(u4, x2), .y = @intCast(u4, x2), }; try expect(s1.x == x1); try expect(s1.y == x1); try expect(s2.x == @intCast(u4, x2)); try expect(s2.y == @intCast(u4, x2)); } var x1 = @as(u4, 1); var x2 = @as(u8, 2); const Nibbles = packed struct { x: u4, y: u4, }; const Bitfields = packed struct { f1: u16, f2: u16, f3: u8, f4: u8, f5: u4, f6: u4, f7: u8, }; test "native bit field understands endianness" { var all: u64 = if (native_endian != .Little) 0x1111222233445677 else 0x7765443322221111; var bytes: [8]u8 = undefined; @memcpy(&bytes, @ptrCast([*]u8, &all), 8); var bitfields = @ptrCast(*Bitfields, &bytes).*; try expect(bitfields.f1 == 0x1111); try expect(bitfields.f2 == 0x2222); try expect(bitfields.f3 == 0x33); try expect(bitfields.f4 == 0x44); try expect(bitfields.f5 == 0x5); try expect(bitfields.f6 == 0x6); try expect(bitfields.f7 == 0x77); } test "implicit cast packed struct field to const ptr" { const LevelUpMove = packed struct { move_id: u9, level: u7, fn toInt(value: u7) u7 { return value; } }; var lup: LevelUpMove = undefined; lup.level = 12; const res = LevelUpMove.toInt(lup.level); try expect(res == 12); } test "zero-bit field in packed struct" { const S = packed struct { x: u10, y: void, }; var x: S = undefined; _ = x; } test "packed struct with non-ABI-aligned field" { const S = packed struct { x: u9, y: u183, }; var s: S = undefined; s.x = 1; s.y = 42; try expect(s.x == 1); try expect(s.y == 42); } const BitField1 = packed struct { a: u3, b: u3, c: u2, }; const bit_field_1 = BitField1{ .a = 1, .b = 2, .c = 3, }; test "bit field access" { var data = bit_field_1; try expect(getA(&data) == 1); try expect(getB(&data) == 2); try expect(getC(&data) == 3); comptime try expect(@sizeOf(BitField1) == 1); data.b += 1; try expect(data.b == 3); data.a += 1; try expect(data.a == 2); try expect(data.b == 3); } fn getA(data: *const BitField1) u3 { return data.a; } fn getB(data: *const BitField1) u3 { return data.b; } fn getC(data: *const BitField1) u2 { return data.c; }