zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

blob 7c5c6532 (10426B) - Raw


      1 const expect = @import("std").testing.expect;
      2 
      3 const Value = union(enum) {
      4     Int: u64,
      5     Array: [9]u8,
      6 };
      7 
      8 const Agg = struct {
      9     val1: Value,
     10     val2: Value,
     11 };
     12 
     13 const v1 = Value{ .Int = 1234 };
     14 const v2 = Value{ .Array = [_]u8{3} ** 9 };
     15 
     16 const err = (anyerror!Agg)(Agg{
     17     .val1 = v1,
     18     .val2 = v2,
     19 });
     20 
     21 const array = [_]Value{
     22     v1,
     23     v2,
     24     v1,
     25     v2,
     26 };
     27 
     28 test "unions embedded in aggregate types" {
     29     switch (array[1]) {
     30         Value.Array => |arr| expect(arr[4] == 3),
     31         else => unreachable,
     32     }
     33     switch ((err catch unreachable).val1) {
     34         Value.Int => |x| expect(x == 1234),
     35         else => unreachable,
     36     }
     37 }
     38 
     39 const Foo = union {
     40     float: f64,
     41     int: i32,
     42 };
     43 
     44 test "basic unions" {
     45     var foo = Foo{ .int = 1 };
     46     expect(foo.int == 1);
     47     foo = Foo{ .float = 12.34 };
     48     expect(foo.float == 12.34);
     49 }
     50 
     51 test "comptime union field access" {
     52     comptime {
     53         var foo = Foo{ .int = 0 };
     54         expect(foo.int == 0);
     55 
     56         foo = Foo{ .float = 42.42 };
     57         expect(foo.float == 42.42);
     58     }
     59 }
     60 
     61 test "init union with runtime value" {
     62     var foo: Foo = undefined;
     63 
     64     setFloat(&foo, 12.34);
     65     expect(foo.float == 12.34);
     66 
     67     setInt(&foo, 42);
     68     expect(foo.int == 42);
     69 }
     70 
     71 fn setFloat(foo: *Foo, x: f64) void {
     72     foo.* = Foo{ .float = x };
     73 }
     74 
     75 fn setInt(foo: *Foo, x: i32) void {
     76     foo.* = Foo{ .int = x };
     77 }
     78 
     79 const FooExtern = extern union {
     80     float: f64,
     81     int: i32,
     82 };
     83 
     84 test "basic extern unions" {
     85     var foo = FooExtern{ .int = 1 };
     86     expect(foo.int == 1);
     87     foo.float = 12.34;
     88     expect(foo.float == 12.34);
     89 }
     90 
     91 const Letter = enum {
     92     A,
     93     B,
     94     C,
     95 };
     96 const Payload = union(Letter) {
     97     A: i32,
     98     B: f64,
     99     C: bool,
    100 };
    101 
    102 test "union with specified enum tag" {
    103     doTest();
    104     comptime doTest();
    105 }
    106 
    107 fn doTest() void {
    108     expect(bar(Payload{ .A = 1234 }) == -10);
    109 }
    110 
    111 fn bar(value: Payload) i32 {
    112     expect(Letter(value) == Letter.A);
    113     return switch (value) {
    114         Payload.A => |x| return x - 1244,
    115         Payload.B => |x| if (x == 12.34) i32(20) else 21,
    116         Payload.C => |x| if (x) i32(30) else 31,
    117     };
    118 }
    119 
    120 const MultipleChoice = union(enum(u32)) {
    121     A = 20,
    122     B = 40,
    123     C = 60,
    124     D = 1000,
    125 };
    126 test "simple union(enum(u32))" {
    127     var x = MultipleChoice.C;
    128     expect(x == MultipleChoice.C);
    129     expect(@enumToInt(@TagType(MultipleChoice)(x)) == 60);
    130 }
    131 
    132 const MultipleChoice2 = union(enum(u32)) {
    133     Unspecified1: i32,
    134     A: f32 = 20,
    135     Unspecified2: void,
    136     B: bool = 40,
    137     Unspecified3: i32,
    138     C: i8 = 60,
    139     Unspecified4: void,
    140     D: void = 1000,
    141     Unspecified5: i32,
    142 };
    143 
    144 test "union(enum(u32)) with specified and unspecified tag values" {
    145     comptime expect(@TagType(@TagType(MultipleChoice2)) == u32);
    146     testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
    147     comptime testEnumWithSpecifiedAndUnspecifiedTagValues(MultipleChoice2{ .C = 123 });
    148 }
    149 
    150 fn testEnumWithSpecifiedAndUnspecifiedTagValues(x: MultipleChoice2) void {
    151     expect(@enumToInt(@TagType(MultipleChoice2)(x)) == 60);
    152     expect(1123 == switch (x) {
    153         MultipleChoice2.A => 1,
    154         MultipleChoice2.B => 2,
    155         MultipleChoice2.C => |v| i32(1000) + v,
    156         MultipleChoice2.D => 4,
    157         MultipleChoice2.Unspecified1 => 5,
    158         MultipleChoice2.Unspecified2 => 6,
    159         MultipleChoice2.Unspecified3 => 7,
    160         MultipleChoice2.Unspecified4 => 8,
    161         MultipleChoice2.Unspecified5 => 9,
    162     });
    163 }
    164 
    165 const ExternPtrOrInt = extern union {
    166     ptr: *u8,
    167     int: u64,
    168 };
    169 test "extern union size" {
    170     comptime expect(@sizeOf(ExternPtrOrInt) == 8);
    171 }
    172 
    173 const PackedPtrOrInt = packed union {
    174     ptr: *u8,
    175     int: u64,
    176 };
    177 test "extern union size" {
    178     comptime expect(@sizeOf(PackedPtrOrInt) == 8);
    179 }
    180 
    181 const ZeroBits = union {
    182     OnlyField: void,
    183 };
    184 test "union with only 1 field which is void should be zero bits" {
    185     comptime expect(@sizeOf(ZeroBits) == 0);
    186 }
    187 
    188 const TheTag = enum {
    189     A,
    190     B,
    191     C,
    192 };
    193 const TheUnion = union(TheTag) {
    194     A: i32,
    195     B: i32,
    196     C: i32,
    197 };
    198 test "union field access gives the enum values" {
    199     expect(TheUnion.A == TheTag.A);
    200     expect(TheUnion.B == TheTag.B);
    201     expect(TheUnion.C == TheTag.C);
    202 }
    203 
    204 test "cast union to tag type of union" {
    205     testCastUnionToTagType(TheUnion{ .B = 1234 });
    206     comptime testCastUnionToTagType(TheUnion{ .B = 1234 });
    207 }
    208 
    209 fn testCastUnionToTagType(x: TheUnion) void {
    210     expect(TheTag(x) == TheTag.B);
    211 }
    212 
    213 test "cast tag type of union to union" {
    214     var x: Value2 = Letter2.B;
    215     expect(Letter2(x) == Letter2.B);
    216 }
    217 const Letter2 = enum {
    218     A,
    219     B,
    220     C,
    221 };
    222 const Value2 = union(Letter2) {
    223     A: i32,
    224     B,
    225     C,
    226 };
    227 
    228 test "implicit cast union to its tag type" {
    229     var x: Value2 = Letter2.B;
    230     expect(x == Letter2.B);
    231     giveMeLetterB(x);
    232 }
    233 fn giveMeLetterB(x: Letter2) void {
    234     expect(x == Value2.B);
    235 }
    236 
    237 pub const PackThis = union(enum) {
    238     Invalid: bool,
    239     StringLiteral: u2,
    240 };
    241 
    242 test "constant packed union" {
    243     testConstPackedUnion([_]PackThis{PackThis{ .StringLiteral = 1 }});
    244 }
    245 
    246 fn testConstPackedUnion(expected_tokens: []const PackThis) void {
    247     expect(expected_tokens[0].StringLiteral == 1);
    248 }
    249 
    250 test "switch on union with only 1 field" {
    251     var r: PartialInst = undefined;
    252     r = PartialInst.Compiled;
    253     switch (r) {
    254         PartialInst.Compiled => {
    255             var z: PartialInstWithPayload = undefined;
    256             z = PartialInstWithPayload{ .Compiled = 1234 };
    257             switch (z) {
    258                 PartialInstWithPayload.Compiled => |x| {
    259                     expect(x == 1234);
    260                     return;
    261                 },
    262             }
    263         },
    264     }
    265     unreachable;
    266 }
    267 
    268 const PartialInst = union(enum) {
    269     Compiled,
    270 };
    271 
    272 const PartialInstWithPayload = union(enum) {
    273     Compiled: i32,
    274 };
    275 
    276 test "access a member of tagged union with conflicting enum tag name" {
    277     const Bar = union(enum) {
    278         A: A,
    279         B: B,
    280 
    281         const A = u8;
    282         const B = void;
    283     };
    284 
    285     comptime expect(Bar.A == u8);
    286 }
    287 
    288 test "tagged union initialization with runtime void" {
    289     expect(testTaggedUnionInit({}));
    290 }
    291 
    292 const TaggedUnionWithAVoid = union(enum) {
    293     A,
    294     B: i32,
    295 };
    296 
    297 fn testTaggedUnionInit(x: var) bool {
    298     const y = TaggedUnionWithAVoid{ .A = x };
    299     return @TagType(TaggedUnionWithAVoid)(y) == TaggedUnionWithAVoid.A;
    300 }
    301 
    302 pub const UnionEnumNoPayloads = union(enum) {
    303     A,
    304     B,
    305 };
    306 
    307 test "tagged union with no payloads" {
    308     const a = UnionEnumNoPayloads{ .B = {} };
    309     switch (a) {
    310         @TagType(UnionEnumNoPayloads).A => @panic("wrong"),
    311         @TagType(UnionEnumNoPayloads).B => {},
    312     }
    313 }
    314 
    315 test "union with only 1 field casted to its enum type" {
    316     const Literal = union(enum) {
    317         Number: f64,
    318         Bool: bool,
    319     };
    320 
    321     const Expr = union(enum) {
    322         Literal: Literal,
    323     };
    324 
    325     var e = Expr{ .Literal = Literal{ .Bool = true } };
    326     const Tag = @TagType(Expr);
    327     comptime expect(@TagType(Tag) == comptime_int);
    328     var t = Tag(e);
    329     expect(t == Expr.Literal);
    330 }
    331 
    332 test "union with only 1 field casted to its enum type which has enum value specified" {
    333     const Literal = union(enum) {
    334         Number: f64,
    335         Bool: bool,
    336     };
    337 
    338     const Tag = enum {
    339         Literal = 33,
    340     };
    341 
    342     const Expr = union(Tag) {
    343         Literal: Literal,
    344     };
    345 
    346     var e = Expr{ .Literal = Literal{ .Bool = true } };
    347     comptime expect(@TagType(Tag) == comptime_int);
    348     var t = Tag(e);
    349     expect(t == Expr.Literal);
    350     expect(@enumToInt(t) == 33);
    351     comptime expect(@enumToInt(t) == 33);
    352 }
    353 
    354 test "@enumToInt works on unions" {
    355     const Bar = union(enum) {
    356         A: bool,
    357         B: u8,
    358         C,
    359     };
    360 
    361     const a = Bar{ .A = true };
    362     var b = Bar{ .B = undefined };
    363     var c = Bar.C;
    364     expect(@enumToInt(a) == 0);
    365     expect(@enumToInt(b) == 1);
    366     expect(@enumToInt(c) == 2);
    367 }
    368 
    369 const Attribute = union(enum) {
    370     A: bool,
    371     B: u8,
    372 };
    373 
    374 fn setAttribute(attr: Attribute) void {}
    375 
    376 fn Setter(attr: Attribute) type {
    377     return struct {
    378         fn set() void {
    379             setAttribute(attr);
    380         }
    381     };
    382 }
    383 
    384 test "comptime union field value equality" {
    385     const a0 = Setter(Attribute{ .A = false });
    386     const a1 = Setter(Attribute{ .A = true });
    387     const a2 = Setter(Attribute{ .A = false });
    388 
    389     const b0 = Setter(Attribute{ .B = 5 });
    390     const b1 = Setter(Attribute{ .B = 9 });
    391     const b2 = Setter(Attribute{ .B = 5 });
    392 
    393     expect(a0 == a0);
    394     expect(a1 == a1);
    395     expect(a0 == a2);
    396 
    397     expect(b0 == b0);
    398     expect(b1 == b1);
    399     expect(b0 == b2);
    400 
    401     expect(a0 != b0);
    402     expect(a0 != a1);
    403     expect(b0 != b1);
    404 }
    405 
    406 test "return union init with void payload" {
    407     const S = struct {
    408         fn entry() void {
    409             expect(func().state == State.one);
    410         }
    411         const Outer = union(enum) {
    412             state: State,
    413         };
    414         const State = union(enum) {
    415             one: void,
    416             two: u32,
    417         };
    418         fn func() Outer {
    419             return Outer{ .state = State{ .one = {} } };
    420         }
    421     };
    422     S.entry();
    423     comptime S.entry();
    424 }
    425 
    426 test "@unionInit can modify a union type" {
    427     const UnionInitEnum = union(enum) {
    428         Boolean: bool,
    429         Byte: u8,
    430     };
    431 
    432     var value: UnionInitEnum = undefined;
    433 
    434     value = @unionInit(UnionInitEnum, "Boolean", true);
    435     expect(value.Boolean == true);
    436     value.Boolean = false;
    437     expect(value.Boolean == false);
    438 
    439     value = @unionInit(UnionInitEnum, "Byte", 2);
    440     expect(value.Byte == 2);
    441     value.Byte = 3;
    442     expect(value.Byte == 3);
    443 }
    444 
    445 test "@unionInit can modify a pointer value" {
    446     const UnionInitEnum = union(enum) {
    447         Boolean: bool,
    448         Byte: u8,
    449     };
    450 
    451     var value: UnionInitEnum = undefined;
    452     var value_ptr = &value;
    453 
    454     value_ptr.* = @unionInit(UnionInitEnum, "Boolean", true);
    455     expect(value.Boolean == true);
    456 
    457     value_ptr.* = @unionInit(UnionInitEnum, "Byte", 2);
    458     expect(value.Byte == 2);
    459 }
    460 
    461 test "union no tag with struct member" {
    462     const Struct = struct {};
    463     const Union = union {
    464         s: Struct,
    465         pub fn foo(self: *@This()) void {}
    466     };
    467     var u = Union{ .s = Struct{} };
    468     u.foo();
    469 }
    470 
    471 fn testComparison() void {
    472     var x = Payload{.A = 42};
    473     expect(x == .A);
    474     expect(x != .B);
    475     expect(x != .C);
    476     expect((x == .B) == false);
    477     expect((x == .C) == false);
    478     expect((x != .A) == false);
    479 }
    480 
    481 test "comparison between union and enum literal" {
    482     testComparison();
    483     comptime testComparison();
    484 }