I was trying to create a graph data structure with Zig. Basically I pass in a union, that contains 1 or more structs as the union fields. Then for each struct of union I add two additional fields id and edges.
So if I pass in a Zig union like this:
const Package: type = union(enum) {
Game: struct {
title: []const u8,
ry: usize,
},
User: struct {
name: []const u8,
age: usize,
},
};
I was expecting to get this:
const Package: type = union(enum) {
Game: struct {
tag: Tag,
edges: []*Edges,
title: []const u8,
ry: usize,
},
User: struct {
tag: Tag,
edges: []*Edge,
name: []const u8,
age: usize,
},
};
This is the whole code:
const std: type = @import("std");
const uuid: type = @import("uuid");
const Type: type = std.builtin.Type;
pub fn Graph(comptime T: type) type {
if (@typeInfo(T) != .Union) @compileError("Invalid Schema");
return comptime struct {
allocator: std.mem.Allocator,
nodes: []*Node,
const Self = @This();
pub const Node: type = @Type(.{ .Union = Type.Union{
.decls = &[_]Type.Declaration{},
.layout = .Auto,
.tag_type = enum {},
.fields = blk: {
var union_fields: [std.meta.fields(T).len]Type.UnionField = undefined;
for (std.meta.fields(T), 0..) |union_field, i| {
const add_fields: []const Type.StructField = &[_]Type.StructField{
.{ .type = uuid.urn, .name = "id", .alignment = 0, .is_comptime = false, .default_value = null },
.{ .type = []Edge, .name = "edges", .alignment = 0, .is_comptime = false, .default_value = null },
};
const new_struct: Type.Struct = .{
.fields = add_fields ++ std.meta.fields(union_field.type),
.decls = &[_]Type.Declaration{},
.layout = .Auto,
.is_tuple = false,
};
union_fields[i] = .{
.name = union_field.name,
.type = @Type(.{ .Struct = new_struct }),
.alignment = 0,
};
}
break :blk &union_fields;
},
} });
pub const Edge: type = struct {
label: []const u8,
nodes: []*Node,
};
pub fn init(alloc: std.mem.Allocator) !*Self {
var graph: *Self = try alloc.create(Self);
graph.allocator = alloc;
graph.nodes = &[0]*Node{};
return graph;
}
pub fn deinit(self: *Self) void {
self.allocator.destroy(self);
}
};
}
But when I did
std.debug.print("{}\n", .{std.meta.fields(Node).len});
I get 0;
I checked this snippet separately:
const fields: []const Type.UnionField = comptime blk: {
var union_fields: [std.meta.fields(T).len]Type.UnionField = undefined;
for (std.meta.fields(T), 0..) |union_field, i| {
const add_fields: []const Type.StructField = &[_]Type.StructField{
.{ .type = uuid.urn, .name = "id", .alignment = 0, .is_comptime = false, .default_value = null },
.{ .type = []Edge, .name = "edges", .alignment = 0, .is_comptime = false, .default_value = null },
};
const new_struct: Type.Struct = .{
.fields = add_fields ++ std.meta.fields(union_field.type),
.decls = &[_]Type.Declaration{},
.layout = .Auto,
.is_tuple = false,
};
union_fields[i] = .{
.name = union_field.name,
.type = @Type(.{ .Struct = new_struct }),
.alignment = 0,
};
}
break :blk &union_fields;
},
And it works as expected. I have been looking for a solution for 2 days and I can’t any.