I would like to take a tuple like .{'1', '2', '3'}
and inject a separator between the items to get, e.g. .{'1', '@', '2', '@', '3'}
. The code below bombs with the following errors.
I’m focused on the separate
function which is meant to do the above by creating a printer const pp1 = separate(space, .{char('@')});
.
sepTypes
is supposed to create the new tuple type.
I’m setting the array of values a
to be of type sepTypes(sep, printers)
.
comptime var a: sepTypes(sep, printers) = undefined;
Why don’t my types match?
main.zig:114:21: error: expected type 'main.Concat(struct { main.Char })', found 'main.Concat(.{ .{ ... } })'
return Concat(a){};
The errors
❯ zig build test --summary all
test
└─ run test
└─ zig test Debug native 2 errors
main.zig:44:25: error: type 'type' is not indexable and not a range
inline for (printers) |p| {
^~~~~~~~
main.zig:44:25: note: for loop operand must be a range, array, slice, tuple, or vector
main.zig:114:21: error: expected type 'main.Concat(struct { main.Char })', found 'main.Concat(.{ .{ ... } })'
return Concat(a){};
~~~~~~~~~^~
main.zig:38:12: note: struct declared here (2 times)
return struct {
^~~~~~
main.zig:101:76: note: function return type declared here
pub fn separate(comptime sep: anytype, comptime printers: anytype) Separate(sep, printers) {
~~~~~~~~^~~~~~~~~~~~~~~ ~~~~~~~~^~~~~~~~~~~~~~~
The code
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 print(_: Self, _: anytype) Error!void {}
};
const empty = Empty{};
const Char = struct {
c: u8,
const Self = @This();
fn print(self: Self, writer: anytype) Error!void {
const s = [_]u8{self.c};
_ = try writer.write(&s);
}
};
pub fn char(comptime c: u8) Char {
if (c == '\n')
@compileError("Newline is invalid!");
return Char{ .c = c };
}
pub const space = char(' ');
pub fn Concat(comptime printers: anytype) type {
return struct {
pub const T = @TypeOf(printers);
const Self = @This();
fn print(_: Self, writer: anytype) Error!void {
inline for (printers) |p| {
const PT = @TypeOf(p);
try PT.print(p, writer);
}
}
};
}
pub fn concat(comptime printers: anytype) Concat(printers) {
return Concat(printers){};
}
test "concat" {
const a = testing.allocator;
const L = std.ArrayList(u8);
var list1 = L.init(a);
defer list1.deinit();
const pp1 = concat(.{empty});
try pp1.print(list1.writer());
try testing.expectEqual(0, list1.items.len);
var list2 = L.init(a);
defer list2.deinit();
const pp2 = concat(.{ empty, space, char('@') });
try pp2.print(list2.writer());
try testing.expectEqual(3, list2.items.len);
try testing.expectEqualSlices(u8, " @", list2.items);
}
fn sepTypes(comptime sep: anytype, comptime printers: anytype) type {
if (printers.len == 0)
@compileError("No printers to separate!");
const len = printers.len;
const n = comptime if (len == 1) 1 else (len * 2 - 1);
comptime var a: [n]type = undefined;
if (len > 1) {
const TS = @TypeOf(sep);
for (0..len - 1) |i| {
const T = @TypeOf(printers[i]);
a[2 * i] = T;
a[2 * 1 + 1] = TS;
}
}
const T = @TypeOf(printers[len - 1]);
a[n - 1] = T;
return meta.Tuple(&a);
}
pub fn Separate(comptime sep: anytype, comptime printers: anytype) type {
const T = sepTypes(sep, printers);
return Concat(T);
}
pub fn separate(comptime sep: anytype, comptime printers: anytype) Separate(sep, printers) {
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 Concat(a){};
}
test "separate" {
const a = testing.allocator;
const L = std.ArrayList(u8);
var list = L.init(a);
const pp1 = separate(space, .{char('@')});
try pp1.print(list.writer());
try testing.expectEqual(1, list.items.len);
const expect1 = "1";
try testing.expectEqualSlices(u8, expect1, list.items);
list.deinit();
// list = L.init(a);
// const pp2 = separate(space, .{ char('1')), char('2') });
// var state2 = State.init(0.5, 80);
// try pp2.print(&state2, list.writer());
// try testing.expectEqual(3, list.items.len);
// const expect2 = "1 2";
// try testing.expectEqualSlices(u8, expect2, list.items);
// list.deinit();
}
pub fn main() !void {}