fediglam/src/util/lib.zig

105 lines
3.3 KiB
Zig

const std = @import("std");
pub const ciutf8 = @import("./ciutf8.zig");
pub const Uuid = @import("./Uuid.zig");
pub const DateTime = @import("./DateTime.zig");
pub const PathIter = @import("./PathIter.zig");
pub const Url = @import("./Url.zig");
pub fn cloneStr(str: []const u8, alloc: std.mem.Allocator) ![]const u8 {
var new = try alloc.alloc(u8, str.len);
std.mem.copy(u8, new, str);
return new;
}
pub fn deepFree(alloc: ?std.mem.Allocator, val: anytype) void {
const T = @TypeOf(val);
switch (@typeInfo(T)) {
.Pointer => |ptr| switch (ptr.size) {
.One => alloc.?.destroy(val),
.Slice => {
for (val) |v| deepFree(alloc, v);
alloc.?.free(val);
},
else => @compileError("Many and C-style pointers not supported by deepfree"),
},
.Optional => if (val) |v| deepFree(alloc, v) else {},
.Struct => |struct_info| inline for (struct_info.fields) |field| deepFree(alloc, @field(val, field.name)),
.Union, .ErrorUnion => @compileError("TODO: Unions not yet supported by deepFree"),
.Array => for (val) |v| deepFree(alloc, v),
.Enum, .Int, .Float, .Bool, .Void, .Type => {},
else => @compileError("Type " ++ @typeName(T) ++ " not supported by deepFree"),
}
}
// deepClone assumes the value owns any pointers inside it
pub fn deepClone(alloc: std.mem.Allocator, val: anytype) !@TypeOf(val) {
const T = @TypeOf(val);
var result: T = undefined;
switch (@typeInfo(T)) {
.Pointer => |ptr| switch (ptr.size) {
.One => {
result = try alloc.create(ptr.child);
errdefer alloc.free(result);
result.* = try deepClone(alloc, val.*);
},
.Slice => {
const slice = try alloc.alloc(ptr.child, val.len);
errdefer alloc.free(slice);
var count: usize = 0;
errdefer for (slice[0..count]) |v| deepFree(alloc, v);
for (val) |v, i| {
slice[i] = try deepClone(alloc, v);
count += 1;
}
result = slice;
},
else => @compileError("Many and C-style pointers not supported"),
},
.Optional => {
result = if (val) |v| try deepClone(alloc, v) else null;
},
.Struct => {
const fields = std.meta.fields(T);
var count: usize = 0;
errdefer {
inline for (fields) |f, i| {
if (i < count) deepFree(alloc, @field(result, f.name));
}
}
inline for (fields) |f| {
@field(result, f.name) = try deepClone(alloc, @field(val, f.name));
count += 1;
}
},
.Array => {
var count: usize = 0;
errdefer for (result[0..count]) |v| deepFree(alloc, v);
for (val) |v, i| {
result[i] = try deepClone(alloc, v);
count += 1;
}
},
.Enum, .Int, .Float, .Bool, .Void, .Type => {
result = val;
},
else => @compileError("Type " ++ @typeName(T) ++ " not supported"),
}
return result;
}
test {
_ = ciutf8;
_ = Uuid;
_ = PathIter;
_ = DateTime;
}