Modify the code somewhat, though, and it stops working (below).
The error is a bit more descriptive, though.
main.zig:130:18: error: expected type 'main.Concat(struct { comptime main.Empty = .{}, comptime main.One = .{}, main.Many, comptime main.One = .{}, comptime main.One = .{} })', found 'main.Concat(.{ undefined, undefined, .{ ... }, undefined, undefined })'
return concat(makesep(sep, printers));
~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
main.zig:45:12: note: struct declared here (2 times)
return struct {
^~~~~~
main.zig:129:76: note: function return type declared here
pub fn separate(comptime sep: anytype, comptime printers: anytype) Separate(sep, printers) {
~~~~~~~~^~~~~~~~~~~~~~~
Why would I get undefined
as a type when assigning to my newly created tuple?
const std = @import("std");
const io = std.io;
const mem = std.mem;
const meta = std.meta;
const testing = std.testing;
pub const Error = error{InvalidNewline} || mem.Allocator.Error;
const Empty = struct {
const Self = @This();
fn width(_: Self) usize {
return 0;
}
};
pub const empty = Empty{};
const One = struct {
const Self = @This();
fn width(_: Self) usize {
return 1;
}
};
pub const one = One{};
const Many = struct {
n: usize,
const Self = @This();
fn width(self: Self) usize {
return self.n;
}
};
pub fn many(comptime n: usize) Many {
return Many{ .n = n };
}
pub fn Concat(comptime printers: anytype) type {
return struct {
pub const T = @TypeOf(printers);
const Self = @This();
fn width(_: Self) usize {
var w: usize = 0;
inline for (printers) |p| {
w += p.width();
}
return w;
}
};
}
pub fn concat(comptime printers: anytype) Concat(printers) {
return Concat(printers){};
}
test "concat" {
const pp = concat(.{ empty, one, many(3) });
std.debug.print("concat: pp = {any}\n", .{@TypeOf(pp)});
try testing.expectEqual(4, pp.width());
}
fn sepTypes(comptime sep: anytype, comptime printers: anytype) type {
const info = switch (@typeInfo(@TypeOf(printers))) {
.@"struct" => |s| s,
else => @compileError("Not a tuple!"),
};
const len = info.fields.len;
if (len == 0)
@compileError("No printers to separate!");
var a: []const type = &[_]type{};
if (len > 1) {
const TS = @TypeOf(sep);
for (0..len - 1) |i| {
const T = @TypeOf(printers[i]);
a = a ++ [_]type{T};
a = a ++ [_]type{TS};
}
}
const T = @TypeOf(printers[len - 1]);
a = a ++ [_]type{T};
return meta.Tuple(a);
}
pub fn makesep(comptime sep: anytype, comptime printers: anytype) sepTypes(sep, printers) {
const info = switch (@typeInfo(@TypeOf(printers))) {
.@"struct" => |s| s,
else => @compileError("Not a tuple!"),
};
const len = info.fields.len;
//const len = printers.len;
const n = comptime if (len == 1) 1 else (len * 2 - 1);
comptime var a: sepTypes(sep, printers) = undefined;
if (len > 1) {
inline for (0..len - 1) |i| {
a[i * 2] = printers[i];
a[i * 2 + 1] = sep;
}
}
a[n - 1] = printers[len - 1];
return a;
}
test "makesep" {
const pp = makesep(10, .{ 20, 30, 40 });
try testing.expectEqual(.{ 10, 10, 30, 10, 40 }, pp);
}
pub fn Separate(comptime sep: anytype, comptime printers: anytype) type {
return Concat(sepTypes(sep, printers));
}
pub fn separate(comptime sep: anytype, comptime printers: anytype) Separate(sep, printers) {
return concat(makesep(sep, printers));
}
test "separate" {
const pp = separate(one, .{ empty, many(3), one });
try testing.expectEqual(5, pp.width());
}
pub fn main() !void {}