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 Project = @import("./Project.zig");
|
||||
|
||||
pub const merge = @import("./Merged.zig").merge;
|
||||
|
||||
test {
|
||||
@import("std").testing.refAllDecls(@This());
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user