Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- const std = @import("std");
- const TypeId = @import("builtin").TypeId;
- const allocPrint = std.fmt.allocPrint;
- // This should be equivalent to Tuple(f32, f32)
- fn TestTuple() type {
- return struct {
- const Self = this;
- const Types = []type { f32, f32 };
- field0: f32,
- field1: f32,
- fn init(arg0: f32, arg1: f32) Self {
- return Self {
- .field0 = arg0,
- .field1 = arg1
- };
- }
- fn get(self: &Self, comptime i: usize) &(@memberType(Self, i)) {
- return if (i == 0) &self.field0 else &self.field1;
- }
- // Takes a series of pointers or nullable pointers and unpacks the tuple fields into them.
- // null pointers are ignored.
- fn unpack(self: &const Self, args: ...) void {
- if (args.len == 0) {
- @compileError("You have to unpack at least one field.");
- }
- if (args.len > Self.Types.len) {
- @compileError("Cannot unpack more fields than the tuple has.");
- }
- comptime var i = 0;
- inline while (i < args.len) : (i += 1) {
- comptime var nullable = false;
- if (@typeId(@typeOf(args[i])) == TypeId.Nullable) {
- nullable = true;
- }
- comptime const arg_type = if (nullable) @typeOf(args[i]).Child else @typeOf(args[i]);
- comptime const type_id = @typeId(arg_type);
- if (type_id != TypeId.Pointer) {
- @compileError("Must pass pointers to unpack.");
- }
- if (arg_type.Child != Self.Types[i]) {
- @compileError("Invalid pointer type.");
- }
- if (nullable) {
- if (args[i] != null) {
- *??args[i] = if (i == 0) self.field0 else self.field1;
- }
- } else {
- *args[i] = if (i == 0) self.field0 else self.field1;
- }
- }
- }
- };
- }
- fn ChildRefType(comptime ref_type: type, comptime i: usize) type {
- // TODO: Check for constness of ref_type, propagate it to the result type
- return &(@memberType(ref_type.Child, i));
- }
- // get the i'th field of a struct
- pub fn get(self: var, comptime i: usize) ChildRefType(@typeOf(self), i) {
- return if (i == 0) &self.field0 else &self.field1;
- }
- pub fn Tuple(comptime types: []type) type {
- if (types.len == 0) {
- @compileError("No types passed to Tuple.");
- }
- var allocator_data: [1024 * 8]u8 = undefined;
- const alloc = &std.heap.FixedBufferAllocator.init(allocator_data).allocator;
- var member_names: [types.len][]const u8 = undefined;
- var member_types: [types.len][]const &TypeInfo = undefined;
- for (types) |t, i| {
- member_names[i] = allocPrint(alloc, "field{}", i) catch unreachable;
- member_types[i] = @reflect(t);
- }
- // Free the member names upon exiting the function.
- defer for (member_names) |m| {
- alloc.free(m);
- };
- // Build our tuple type.
- // These types should be builtin so no need for import, right?
- const struct_detail = StructTypeInfoDetail.init(false, member_names, member_types);
- const detail = TypeInfoDetail {
- .Struct = struct_detail
- };
- // Perhaps:
- // const detail = TypeInfoDetail.init(TypeId.Struct, false, member_names, member_types);
- // TODO: Add methods
- // init(args: ...), get(comptime i: usize) &types[i], ...
- const type_info = TypeInfo.init(false, false, detail);
- return @reify(type_info);
- // TODO: Better TypeBuilder interface, look at the TypeId's currently available.
- // var builder = TypeBuilder.init();
- // builder.buildTypeAndStuff();
- // @reify(builder)
- }
- fn vararg_types(args: ...) []type {
- var ts: [args.len]type = undefined;
- var i = 0;
- while (i < args.len) : (i += 1) {
- ts[i] = @typeOf(args[i]);
- }
- return ts;
- }
- pub fn make_tuple(args: ...) Tuple(vararg_types(args)) {
- const TupleType = @typeOf(this).ReturnType;
- var tup: TupleType = undefined;
- inline for (args) |arg, i| {
- *tup.get(i) = arg;
- }
- return tup;
- }
- pub fn main() !void {
- var stdout_file = try std.io.getStdOut();
- var adapter = std.io.FileOutStream.init(&stdout_file);
- var stream = &adapter.stream;
- const Point = TestTuple();
- //const Point = Tuple(f32, f32);
- var p = Point.init(0.0, 0.0);
- try stream.print("({}, {})\n", *p.get(0), *p.get(1));
- *p.get(0) = 1.0;
- try stream.print("({}, {})\n", *p.get(0), *p.get(1));
- *get(p, 1) = 1.0;
- try stream.print("({}, {})\n", *p.get(0), *p.get(1));
- *p.get(1) = 2.0;
- var to_unpack: f32 = undefined;
- var nullable: ?&f32 = null;
- p.unpack(nullable, &to_unpack);
- try stream.print("UNPACKED {}\n", to_unpack);
- // const pp = Point.init(1.0, 1.0);
- // *get(pp, 0) = 2.0;
- }
Add Comment
Please, Sign In to add comment