Compares two of any type for equality. Containers that do not support comparison on their own are compared on a field-by-field basis. Pointers are not followed.
pub fn eql(a: anytype, b: @TypeOf(a)) bool
pub fn eql(a: anytype, b: @TypeOf(a)) bool {
const T = @TypeOf(a);
switch (@typeInfo(T)) {
.@"struct" => |info| {
if (info.layout == .@"packed") return a == b;
inline for (info.field_names) |field_name| {
if (!eql(@field(a, field_name), @field(b, field_name))) return false;
}
return true;
},
.error_union => {
if (a) |a_p| {
if (b) |b_p| return eql(a_p, b_p) else |_| return false;
} else |a_e| {
if (b) |_| return false else |b_e| return a_e == b_e;
}
},
.@"union" => |info| {
if (info.layout == .@"packed") return a == b;
const UnionTag = info.tag_type orelse
@compileError("cannot compare untagged union type " ++ @typeName(T));
const tag_a: UnionTag = a;
const tag_b: UnionTag = b;
if (tag_a != tag_b) return false;
return switch (a) {
inline else => |val, tag| return eql(val, @field(b, @tagName(tag))),
};
},
.array => {
for (a, b) |x, y| {
if (!eql(x, y)) return false;
}
return true;
},
.vector => return @reduce(.And, a == b),
.pointer => |info| {
return switch (info.size) {
.one, .many, .c => a == b,
.slice => a.ptr == b.ptr and a.len == b.len,
};
},
.optional => {
const some_a = a orelse return b == null;
const some_b = b orelse return false;
return eql(some_a, some_b);
},
else => return a == b,
}
}