diff options
Diffstat (limited to '')
-rw-r--r-- | src/string.zig | 163 |
1 files changed, 159 insertions, 4 deletions
diff --git a/src/string.zig b/src/string.zig index f09428f69..cf4109d40 100644 --- a/src/string.zig +++ b/src/string.zig @@ -250,6 +250,15 @@ pub const String = extern struct { return BunString__fromBytes(bytes.ptr, bytes.len); } + pub fn isEmpty(this: String) bool { + return this.tag == .Empty or this.length() == 0; + } + + pub fn dupeRef(this: String) String { + this.ref(); + return this; + } + pub fn initWithType(comptime Type: type, value: Type) String { switch (comptime Type) { ZigString => return String{ .tag = .ZigString, .value = .{ .ZigString = value } }, @@ -337,6 +346,24 @@ pub const String = extern struct { return BunString__toJS(globalObject, this); } + pub fn toJSConst(this: *const String, globalObject: *bun.JSC.JSGlobalObject) JSC.JSValue { + JSC.markBinding(@src()); + var a = this.*; + return toJS(&a, globalObject); + } + + extern fn BunString__createArray( + globalObject: *bun.JSC.JSGlobalObject, + ptr: [*]const String, + len: usize, + ) JSC.JSValue; + + pub fn toJSArray(globalObject: *bun.JSC.JSGlobalObject, array: []const bun.String) JSC.JSValue { + JSC.markBinding(@src()); + + return BunString__createArray(globalObject, array.ptr, array.len); + } + pub fn toZigString(this: String) ZigString { if (this.tag == .StaticZigString or this.tag == .ZigString) { return this.value.ZigString; @@ -449,6 +476,13 @@ pub const String = extern struct { return ZigString.Slice.empty; } + pub fn toSlice(this: String, allocator: std.mem.Allocator) SliceWithUnderlyingString { + return SliceWithUnderlyingString{ + .utf8 = this.toUTF8(allocator), + .underlying = this, + }; + } + extern fn BunString__fromJS(globalObject: *JSC.JSGlobalObject, value: bun.JSC.JSValue, out: *String) bool; extern fn BunString__toJS(globalObject: *JSC.JSGlobalObject, in: *String) JSC.JSValue; extern fn BunString__toWTFString(this: *String) void; @@ -473,11 +507,114 @@ pub const String = extern struct { return this.toZigString().eqlComptime(value); } + pub fn is8Bit(this: String) bool { + return switch (this.tag) { + .WTFStringImpl => this.value.WTFStringImpl.is8Bit(), + .ZigString => !this.value.ZigString.is16Bit(), + else => true, + }; + } + + pub fn indexOfComptimeWithCheckLen(this: String, comptime values: []const []const u8, comptime check_len: usize) ?usize { + if (this.is8Bit()) { + const bytes = this.byteSlice(); + for (values, 0..) |val, i| { + if (bun.strings.eqlComptimeCheckLenWithType(u8, bytes, val, check_len)) { + return i; + } + } + + return null; + } + + const u16_bytes = this.byteSlice(); + inline for (values, 0..) |val, i| { + if (bun.strings.eqlComptimeCheckLenWithType(u16, u16_bytes, comptime bun.strings.toUTF16Literal(val), check_len)) { + return i; + } + } + + return null; + } + + pub fn indexOfComptimeArrayAssumeSameLength(this: String, comptime values: []const []const u8) ?usize { + if (this.is8Bit()) { + const bytes = this.byteSlice(); + + inline for (0..values.len) |i| { + std.debug.assert(bytes.len == values[i].len); + if (bun.strings.eqlComptimeCheckLenWithType(u8, bytes, values[i], false)) { + return i; + } + } + + return null; + } + + const u16_bytes = this.utf16(); + var buffer: [values[0].len]u8 = undefined; + inline for (0..values[0].len) |i| { + const uchar = u16_bytes[i]; + if (uchar > 255) + return null; + + buffer[i] = @intCast(u8, uchar); + } + + inline for (0..values.len) |i| { + if (bun.strings.eqlComptimeCheckLenWithType(u8, &buffer, values[i], false)) { + return i; + } + } + + return null; + } + + pub fn inMap(this: String, comptime ComptimeStringMap: anytype) ?ComptimeStringMap.Value { + return ComptimeStringMap.getWithEqlList(this, indexOfComptimeArrayAssumeSameLength); + } + + pub fn inMapCaseInsensitive(this: String, comptime ComptimeStringMap: anytype) ?ComptimeStringMap.Value { + return ComptimeStringMap.getWithEqlList(this, indexOfComptimeArrayCaseInsensitiveSameLength); + } + + pub fn indexOfComptimeArrayCaseInsensitiveSameLength(this: String, comptime values: []const []const u8) ?usize { + if (this.is8Bit()) { + const bytes = this.byteSlice(); + + inline for (0..values.len) |i| { + std.debug.assert(bytes.len == values[i].len); + if (bun.strings.eqlCaseInsensitiveASCIIIgnoreLength(bytes, values[i])) { + return i; + } + } + + return null; + } + + const u16_bytes = this.utf16(); + const buffer: [values[0].len]u8 = brk: { + var bytes: [values[0].len]u8 = undefined; + for (&bytes, u16_bytes) |*byte, uchar| { + if (uchar > 255) + return null; + + byte.* = @intCast(u8, uchar); + } + break :brk bytes; + }; + + inline for (0..values.len) |i| { + if (bun.strings.eqlCaseInsensitiveASCIIIgnoreLength(&buffer, values[i])) { + return i; + } + } + + return null; + } + pub fn hasPrefixComptime(this: String, comptime value: []const u8) bool { - _ = value; - _ = this; - return false; - // return this.toZigString().substring(0, value.len).eqlComptime(value); + return this.toZigString().substring(0, value.len).eqlComptime(value); } pub fn isWTFAllocator(this: std.mem.Allocator) bool { @@ -492,3 +629,21 @@ pub const String = extern struct { return this.toZigString().eql(other.toZigString()); } }; + +pub const SliceWithUnderlyingString = struct { + utf8: ZigString.Slice, + underlying: String, + + pub fn deinit(this: SliceWithUnderlyingString) void { + this.utf8.deinit(); + this.underlying.deref(); + } + + pub fn slice(this: SliceWithUnderlyingString) []const u8 { + return this.utf8.slice(); + } + + pub fn toJS(this: SliceWithUnderlyingString, globalObject: *JSC.JSGlobalObject) JSC.JSValue { + return this.underlying.toJS(globalObject); + } +}; |