Makes a Variant holding value; its type picks the case.
#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.
#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#
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.
Whether the live case is T.
The position of the live case in the type's case list.
#import "Extensions/Variant";
id := variant(Variant(s64, string), "abc");
assert(variant_index(id) == 1);↗The type of the live case.
#import "Extensions/Variant";
id := variant(Variant(s64, string), "abc");
assert(variant_type(id) == string);↗A copy of the T payload and true; a zeroed T and false when another case is live.
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);↗The T payload; asserts that T is the live case. Use get when the case is not certain.
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.
The negation of ==.
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));↗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");↗The payload as text, allocated with context.allocator.
#import "Extensions/Variant";
id := variant(Variant(s64, string), cast(s64) 42);
assert(variant_to_string(id) == "42");↗Whether info is an instantiation of Variant.
The types of the cases of a Variant, in order.
Types#
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);↗