Modules

Variant

moduleextensionSource

Available on macOS, Linux, Windows, Wasm·since 0.29.0

#import "Extensions/Variant";

A tagged union whose cases are types. variant and set store a value, is, get and unwrap read it back, and variant_switch runs a handler per case.

Example↗
#import "Extensions/Variant";

Number_Or_Text :: Variant(s64, string);

v := variant(Number_Or_Text, 42);       // the case is the type of the value
w: Number_Or_Text;                      // zeroed first case
set(*w, "hi");                          // switches case

if is(v, s64) print("%\n", unwrap(v, s64));

variant_switch(v,                       // every case needs a handler, checked at compile time
    (it: *s64)    { print("number %\n", it.*); },
    (it: *string) { print("text %\n", it.*); },
);

Two cases of one type are not allowed: wrap each in its own struct.

Procedures#

variantsince 0.29.0Source
($V: Type, value: $T) -> V

Makes a Variant holding value; its type picks the case.

#import "Extensions/Variant";

Id :: Variant(s64, string);
id := variant(Id, "abc");
assert(is(id, string));
↗
setsince 0.29.0Source
(v: *$V/Variant, value: $T)

Stores value as the live case, replacing whatever was there without releasing it (see free_variant). It is a compile-time error when T is not a case.

#import "Extensions/Variant";

Id :: Variant(s64, string);
id: Id;
set(*id, "abc");
set(*id, cast(s64) 7);
assert(unwrap(id, s64) == 7);
↗
issince 0.29.0Source
(v: $V/Variant, $T: Type) -> bool

Whether the live case is T.

#import "Extensions/Variant";

id := variant(Variant(s64, string), "abc");
assert(is(id, string) && !is(id, s64));
↗
getsince 0.29.0Source
(v: $V/Variant, $T: Type) -> (T, bool)

A copy of the T payload and true; a zeroed T and false when another case is live.

#import "Extensions/Variant";

id := variant(Variant(s64, string), "abc");
text, ok := get(id, string);
assert(ok && text == "abc");
_, ok = get(id, s64);
assert(!ok);
↗
get_pointersince 0.29.0Source
(v: *$V/Variant, $T: Type) -> *T

A pointer to the T payload inside the variant, or null when another case is live. It stays valid until the variant is set again, freed or moved.

#import "Extensions/Variant";

id := variant(Variant(s64, string), cast(s64) 1);
number := get_pointer(*id, s64);
number.* += 1;
assert(unwrap(id, s64) == 2);
assert(get_pointer(*id, string) == null);
↗
unwrapsince 0.29.0Source
(v: $V/Variant, $T: Type) -> T

The T payload; asserts that T is the live case. Use get when the case is not certain.

#import "Extensions/Variant";

id := variant(Variant(s64, string), cast(s64) 5);
assert(unwrap(id, s64) == 5);
↗
operator==since 0.29.0Source
(a: $V/Variant, b: V) -> bool

The live case is equal: the same index and equal payloads. Strings compare by content, arrays element by element, structs member by member; pointers by address.

#import "Extensions/Variant";

Id :: Variant(s64, string);
assert(variant(Id, "a") == variant(Id, "a"));
assert(variant(Id, "a") != variant(Id, cast(s64) 1));
↗
free_variantsince 0.29.0Source
(v: *$V/Variant)

Releases the memory the live case owns, with free: strings, resizable arrays (and what their elements own), and the same inside structs and nested variants. Views ([] T) and pointers are not owned and are left alone. Then the variant is zeroed: its first case, zeroed. Only use it on payloads that came from the allocator, not string literals.

#import "Extensions/Variant";

id := variant(Variant(s64, string), copy_string("owned"));
free_variant(*id);
assert(is(id, s64));
↗
(builder: *String_Builder, any: Any, data: *void) -> bool

A Print_Style struct_printer that writes a Variant as its live payload, and passes everything else to the printer that was installed before use_variant_printing (or declines).

()

Makes print("%", variant) write the payload, from now on in this context. Calling it again does nothing; a struct_printer installed earlier still gets the values that are not variants.

#import "Extensions/Variant";

use_variant_printing();
id := variant(Variant(s64, string), "abc");
assert(tprint("%", id) == "abc");
↗
(info: *Type_Info) -> bool

Whether info is an instantiation of Variant.

(info: *Type_Info) -> [] *Type_Info

The types of the cases of a Variant, in order.

Types#

Variantstructsince 0.29.0Source
:: struct

A value that holds one of types at a time. A fresh one holds a zeroed first case; it takes the size of the largest case.

index: s32
The position of the live case in types.
#import "Extensions/Variant";

Id :: Variant(s64, string);
id: Id;
assert(is(id, s64) && variant_index(id) == 0);
set(*id, "abc");
assert(variant_index(id) == 1);
↗

Constants#