add Merged() util
This commit is contained in:
		
							
								
								
									
										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()); | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user