add Merged() util
This commit is contained in:
parent
ca3d26a18d
commit
8d53a185a4
72
src/hncore/Merged.zig
Normal file
72
src/hncore/Merged.zig
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
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);
|
||||||
|
}
|
@ -2,6 +2,8 @@ pub const Mindmap = @import("./Mindmap.zig");
|
|||||||
pub const Node = @import("./Node.zig");
|
pub const Node = @import("./Node.zig");
|
||||||
pub const Project = @import("./Project.zig");
|
pub const Project = @import("./Project.zig");
|
||||||
|
|
||||||
|
pub const merge = @import("./Merged.zig").merge;
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@import("std").testing.refAllDecls(@This());
|
@import("std").testing.refAllDecls(@This());
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user