diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/bun.js/api/bun.zig | 2 | ||||
-rw-r--r-- | src/bun.zig | 130 | ||||
-rw-r--r-- | src/darwin_c.zig | 5 |
3 files changed, 132 insertions, 5 deletions
diff --git a/src/bun.js/api/bun.zig b/src/bun.js/api/bun.zig index 5b4035256..6b5612c18 100644 --- a/src/bun.js/api/bun.zig +++ b/src/bun.js/api/bun.zig @@ -1552,7 +1552,7 @@ pub const Crypto = struct { _ = BoringSSL.ERR_error_string_n(err_code, message_buf, message_buf.len); - const error_message: []const u8 = bun.span(std.meta.assumeSentinel(&outbuf, 0)); + const error_message: []const u8 = bun.sliceTo(outbuf[0..], 0); if (error_message.len == "BoringSSL error: ".len) { return ZigString.static("Unknown BoringSSL error").toErrorInstance(globalThis); } diff --git a/src/bun.zig b/src/bun.zig index b6c0e2c4a..cf3ea67a5 100644 --- a/src/bun.zig +++ b/src/bun.zig @@ -252,8 +252,14 @@ pub fn len(value: anytype) usize { .Array => |info| info.len, .Vector => |info| info.len, .Pointer => |info| switch (info.size) { - .One => switch (@typeInfo(info.child)) { - .Array => value.len, + .One => switch (@as(@import("builtin").TypeInfo, @typeInfo(info.child))) { + .Array => |array| brk: { + if (array.sentinel != null) { + @compileError("use bun.sliceTo"); + } + + break :brk array.len; + }, else => @compileError("invalid type given to std.mem.len"), }, .Many => { @@ -807,3 +813,123 @@ pub fn getFdPath(fd: std.os.fd_t, buf: *[@This().MAX_PATH_BYTES]u8) ![]u8 { return err; }; } + +fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize { + switch (@typeInfo(@TypeOf(ptr))) { + .Pointer => |ptr_info| switch (ptr_info.size) { + .One => switch (@typeInfo(ptr_info.child)) { + .Array => |array_info| { + if (array_info.sentinel) |sentinel_ptr| { + const sentinel = @ptrCast(*align(1) const array_info.child, sentinel_ptr).*; + if (sentinel == end) { + return indexOfSentinel(array_info.child, end, ptr); + } + } + return std.mem.indexOfScalar(array_info.child, ptr, end) orelse array_info.len; + }, + else => {}, + }, + .Many => if (ptr_info.sentinel) |sentinel_ptr| { + const sentinel = @ptrCast(*align(1) const ptr_info.child, sentinel_ptr).*; + // We may be looking for something other than the sentinel, + // but iterating past the sentinel would be a bug so we need + // to check for both. + var i: usize = 0; + while (ptr[i] != end and ptr[i] != sentinel) i += 1; + return i; + }, + .C => { + std.debug.assert(ptr != null); + return indexOfSentinel(ptr_info.child, end, ptr); + }, + .Slice => { + if (ptr_info.sentinel) |sentinel_ptr| { + const sentinel = @ptrCast(*align(1) const ptr_info.child, sentinel_ptr).*; + if (sentinel == end) { + return indexOfSentinel(ptr_info.child, sentinel, ptr); + } + } + return std.mem.indexOfScalar(ptr_info.child, ptr, end) orelse ptr.len; + }, + }, + else => {}, + } + @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(@TypeOf(ptr))); +} + +/// Helper for the return type of sliceTo() +fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type { + switch (@typeInfo(T)) { + .Optional => |optional_info| { + return ?SliceTo(optional_info.child, end); + }, + .Pointer => |ptr_info| { + var new_ptr_info = ptr_info; + new_ptr_info.size = .Slice; + switch (ptr_info.size) { + .One => switch (@typeInfo(ptr_info.child)) { + .Array => |array_info| { + new_ptr_info.child = array_info.child; + // The return type must only be sentinel terminated if we are guaranteed + // to find the value searched for, which is only the case if it matches + // the sentinel of the type passed. + if (array_info.sentinel) |sentinel_ptr| { + const sentinel = @ptrCast(*align(1) const array_info.child, sentinel_ptr).*; + if (end == sentinel) { + new_ptr_info.sentinel = &end; + } else { + new_ptr_info.sentinel = null; + } + } + }, + else => {}, + }, + .Many, .Slice => { + // The return type must only be sentinel terminated if we are guaranteed + // to find the value searched for, which is only the case if it matches + // the sentinel of the type passed. + if (ptr_info.sentinel) |sentinel_ptr| { + const sentinel = @ptrCast(*align(1) const ptr_info.child, sentinel_ptr).*; + if (end == sentinel) { + new_ptr_info.sentinel = &end; + } else { + new_ptr_info.sentinel = null; + } + } + }, + .C => { + new_ptr_info.sentinel = &end; + // C pointers are always allowzero, but we don't want the return type to be. + std.debug.assert(new_ptr_info.is_allowzero); + new_ptr_info.is_allowzero = false; + }, + } + return @Type(.{ .Pointer = new_ptr_info }); + }, + else => {}, + } + @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(T)); +} + +/// Takes an array, a pointer to an array, a sentinel-terminated pointer, or a slice and +/// iterates searching for the first occurrence of `end`, returning the scanned slice. +/// If `end` is not found, the full length of the array/slice/sentinel terminated pointer is returned. +/// If the pointer type is sentinel terminated and `end` matches that terminator, the +/// resulting slice is also sentinel terminated. +/// Pointer properties such as mutability and alignment are preserved. +/// C pointers are assumed to be non-null. +pub fn sliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) SliceTo(@TypeOf(ptr), end) { + if (@typeInfo(@TypeOf(ptr)) == .Optional) { + const non_null = ptr orelse return null; + return sliceTo(non_null, end); + } + const Result = SliceTo(@TypeOf(ptr), end); + const length = lenSliceTo(ptr, end); + const ptr_info = @typeInfo(Result).Pointer; + if (ptr_info.sentinel) |s_ptr| { + const s = @ptrCast(*align(1) const ptr_info.child, s_ptr).*; + return ptr[0..length :s]; + } else { + return ptr[0..length]; + } +} diff --git a/src/darwin_c.zig b/src/darwin_c.zig index 5fe343bc0..474e3374f 100644 --- a/src/darwin_c.zig +++ b/src/darwin_c.zig @@ -1,4 +1,5 @@ const std = @import("std"); +const bun = @import("bun"); const builtin = @import("builtin"); const os = std.os; const mem = std.mem; @@ -568,7 +569,7 @@ pub fn get_version(buf: []u8) []const u8 { 0, ) == -1) return "unknown"; - return std.mem.span(std.meta.assumeSentinel(buf.ptr, 0)); + return bun.sliceTo(buf, 0); } pub fn get_release(buf: []u8) []const u8 { @@ -584,7 +585,7 @@ pub fn get_release(buf: []u8) []const u8 { 0, ) == -1) return "unknown"; - return std.mem.span(std.meta.assumeSentinel(buf.ptr, 0)); + return bun.sliceTo(buf, 0); } const IO_CTL_RELATED = struct { |