diff options
Diffstat (limited to 'src/bun.zig')
-rw-r--r-- | src/bun.zig | 99 |
1 files changed, 98 insertions, 1 deletions
diff --git a/src/bun.zig b/src/bun.zig index 0e5c87991..a93b3c5ae 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -664,7 +664,7 @@ pub fn StringEnum(comptime Type: type, comptime Map: anytype, value: []const u8) pub const Bunfig = @import("./bunfig.zig").Bunfig; -pub const HTTPThead = @import("./http_client_async.zig").HTTPThread; +pub const HTTPThread = @import("./http_client_async.zig").HTTPThread; pub const Analytics = @import("./analytics/analytics_thread.zig"); @@ -1841,3 +1841,100 @@ pub fn fdi32(fd_: anytype) i32 { } pub const OSPathSlice = if (Environment.isWindows) [:0]const u16 else [:0]const u8; +pub const LazyBoolValue = enum { + unknown, + no, + yes, +}; +/// Create a lazily computed boolean value. +/// Getter must be a function that takes a pointer to the parent struct and returns a boolean. +/// Parent must be a type which contains the field we are getting. +pub fn LazyBool(comptime Getter: anytype, comptime Parent: type, comptime field: string) type { + return struct { + value: LazyBoolValue = .unknown, + pub fn get(self: *@This()) bool { + if (self.value == .unknown) { + self.value = switch (Getter(@fieldParentPtr(Parent, field, self))) { + true => .yes, + false => .no, + }; + } + + return self.value == .yes; + } + }; +} + +pub fn serializable(input: anytype) @TypeOf(input) { + const T = @TypeOf(input); + comptime { + if (std.meta.trait.isExtern(T)) { + if (@typeInfo(T) == .Union) { + @compileError("Extern unions must be serialized with serializableInto"); + } + } + } + var zeroed: [@sizeOf(T)]u8 align(@alignOf(T)) = comptime brk: { + var buf: [@sizeOf(T)]u8 align(@alignOf(T)) = undefined; + for (&buf) |*ptr| { + ptr.* = 0; + } + break :brk buf; + }; + const result: *T = @ptrCast(&zeroed); + + inline for (comptime std.meta.fieldNames(T)) |field_name| { + @field(result, field_name) = @field(input, field_name); + } + + return result.*; +} + +pub inline fn serializableInto(comptime T: type, init: anytype) T { + var zeroed: [@sizeOf(T)]u8 align(@alignOf(T)) = comptime brk: { + var buf: [@sizeOf(T)]u8 align(@alignOf(T)) = undefined; + for (&buf) |*ptr| { + ptr.* = 0; + } + break :brk buf; + }; + const result: *T = @ptrCast(&zeroed); + + inline for (comptime std.meta.fieldNames(@TypeOf(init))) |field_name| { + @field(result, field_name) = @field(init, field_name); + } + + return result.*; +} + +/// Like std.fs.Dir.makePath except instead of infinite looping on dangling +/// symlink, it deletes the symlink and tries again. +pub fn makePath(dir: std.fs.Dir, sub_path: []const u8) !void { + var it = try std.fs.path.componentIterator(sub_path); + var component = it.last() orelse return; + while (true) { + dir.makeDir(component.path) catch |err| switch (err) { + error.PathAlreadyExists => { + var path_buf2: [MAX_PATH_BYTES * 2]u8 = undefined; + copy(u8, &path_buf2, component.path); + + path_buf2[component.path.len] = 0; + var path_to_use = path_buf2[0..component.path.len :0]; + const result = sys.lstat(path_to_use); + try result.throw(); + const is_dir = std.os.S.ISDIR(result.result.mode); + // dangling symlink + if (!is_dir) { + dir.deleteTree(component.path) catch {}; + continue; + } + }, + error.FileNotFound => |e| { + component = it.previous() orelse return e; + continue; + }, + else => |e| return e, + }; + component = it.next() orelse return; + } +} |