73 lines
2.1 KiB
Zig
73 lines
2.1 KiB
Zig
const std = @import("std");
|
|
|
|
/// Returns a type having fields that type A and type B have.
|
|
/// Fields from B are more preferred than from A in case that field names are duplicated.
|
|
pub fn Merged(comptime A: type, comptime B: type) type {
|
|
const at = @typeInfo(A).@"struct";
|
|
const bt = @typeInfo(B).@"struct";
|
|
|
|
return @Type(.{
|
|
.@"struct" = .{
|
|
.layout = .auto,
|
|
.fields = mergeFields(at.fields, bt.fields),
|
|
.is_tuple = false,
|
|
.decls = &.{},
|
|
},
|
|
});
|
|
}
|
|
fn mergeFields(
|
|
comptime a: []const std.builtin.Type.StructField,
|
|
comptime b: []const std.builtin.Type.StructField) []std.builtin.Type.StructField {
|
|
var ret: [a.len+b.len]std.builtin.Type.StructField = undefined;
|
|
var len: usize = 0;
|
|
|
|
inline for (b) |f| {
|
|
ret[len] = f;
|
|
ret[len].is_comptime = false;
|
|
len += 1;
|
|
}
|
|
inline for (a) |f| {
|
|
inline for (b) |fb| {
|
|
if (std.mem.eql(u8, f.name, fb.name)) {
|
|
break;
|
|
}
|
|
} else {
|
|
ret[len] = f;
|
|
ret[len].is_comptime = false;
|
|
len += 1;
|
|
}
|
|
}
|
|
return ret[0..len];
|
|
}
|
|
|
|
/// Same to `Merged(@TypeOf(a), @TypeOf(b))` but returns a merged value, not type.
|
|
pub fn merge(a: anytype, b: anytype) Merged(@TypeOf(a), @TypeOf(b)) {
|
|
var ret: Merged(@TypeOf(a), @TypeOf(b)) = undefined;
|
|
|
|
const af = @typeInfo(@TypeOf(a)).@"struct".fields;
|
|
const bf = @typeInfo(@TypeOf(b)).@"struct".fields;
|
|
|
|
inline for (bf) |f| {
|
|
@field(ret, f.name) = @field(b, f.name);
|
|
}
|
|
inline for (af) |f| {
|
|
inline for (bf) |fb| {
|
|
if (std.mem.eql(u8, f.name, fb.name)) {
|
|
break;
|
|
}
|
|
} else {
|
|
@field(ret, f.name) = @field(a, f.name);
|
|
}
|
|
}
|
|
return ret;
|
|
|
|
}
|
|
|
|
test "merging 2 structs" {
|
|
const merged = merge(.{.a = 0, .b = 1, .c = 2,}, .{.b = 44, .d = 53,});
|
|
try std.testing.expect(merged.a == 0);
|
|
try std.testing.expect(merged.b == 44);
|
|
try std.testing.expect(merged.c == 2);
|
|
try std.testing.expect(merged.d == 53);
|
|
}
|