Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/bun.js/bindings/ZigString.zig
Original file line number Diff line number Diff line change
Expand Up @@ -412,7 +412,7 @@ pub const ZigString = extern struct {
}

pub fn mut(this: Slice) []u8 {
return @as([*]u8, @ptrFromInt(@intFromPtr(this.ptr)))[0..this.len];
return @as([*]u8, @constCast(this.ptr))[0..this.len];
}
Comment on lines 414 to 417

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thankfully this function looks unused, so we should delete


/// Does nothing if the slice is not allocated
Expand Down
20 changes: 3 additions & 17 deletions src/bun.js/webcore/Blob.zig
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ content_type_was_set: bool = false,

/// JavaScriptCore strings are either latin1 or UTF-16
/// When UTF-16, they're nearly always due to non-ascii characters
charset: Charset = .unknown,
charset: strings.AsciiStatus = .unknown,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should charset be renamed to ascii_status or is_ascii?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe. I think it's okay. charset == .all_ascii etc. still make sense.


/// Was it created via file constructor?
is_jsdom_file: bool = false,
Expand Down Expand Up @@ -3244,7 +3244,7 @@ pub fn initWithAllASCII(bytes: []u8, allocator: std.mem.Allocator, globalThis: *
.store = store,
.content_type = "",
.globalThis = globalThis,
.charset = .fromIsAllASCII(is_all_ascii),
.charset = .fromBool(is_all_ascii),
};
}

Expand Down Expand Up @@ -3423,7 +3423,7 @@ pub fn sharedView(this: *const Blob) []const u8 {
pub const Lifetime = jsc.WebCore.Lifetime;

pub fn setIsASCIIFlag(this: *Blob, is_all_ascii: bool) void {
this.charset = .fromIsAllASCII(is_all_ascii);
this.charset = .fromBool(is_all_ascii);
// if this Blob represents the entire binary data
// which will be pretty common
// we can update the store's is_all_ascii flag
Expand Down Expand Up @@ -4735,20 +4735,6 @@ pub fn FileCloser(comptime This: type) type {
};
}

/// This takes up less space than a `?bool`.
pub const Charset = enum {
unknown,
all_ascii,
non_ascii,

pub fn fromIsAllASCII(is_all_ascii: ?bool) Charset {
return if (is_all_ascii orelse return .unknown)
.all_ascii
else
.non_ascii;
}
};

pub fn isAllASCII(self: *const Blob) ?bool {
return switch (self.charset) {
.unknown => null,
Expand Down
52 changes: 37 additions & 15 deletions src/string.zig
Original file line number Diff line number Diff line change
Expand Up @@ -74,27 +74,48 @@ pub const String = extern struct {
return BunString__transferToJS(this, globalThis);
}

pub fn toOwnedSlice(this: String, allocator: std.mem.Allocator) ![]u8 {
const bytes, _ = try this.toOwnedSliceReturningAllASCII(allocator);
pub fn toOwnedSlice(this: String, allocator: std.mem.Allocator) OOM![]u8 {
const bytes, _ = try this.toOwnedSliceImpl(allocator);
return bytes;
}

/// Returns `.{ utf8_bytes, is_all_ascii }`.
///
/// `false` means the string contains at least one non-ASCII character.
pub fn toOwnedSliceReturningAllASCII(this: String, allocator: std.mem.Allocator) OOM!struct { []u8, bool } {
switch (this.tag) {
.ZigString => return .{ try this.value.ZigString.toOwnedSlice(allocator), true },
.WTFStringImpl => {
var utf8_slice = this.value.WTFStringImpl.toUTF8WithoutRef(allocator);
if (utf8_slice.allocator.get()) |alloc| {
if (!isWTFAllocator(alloc)) {
return .{ @constCast(utf8_slice.slice()), false };
}
}
const bytes, const ascii_status = try this.toOwnedSliceImpl(allocator);
const is_ascii = switch (ascii_status) {
.all_ascii => true,
.non_ascii => false,
.unknown => bun.strings.isAllASCII(bytes),
};
return .{ bytes, is_ascii };
}

return .{ @constCast((try utf8_slice.cloneIfNeeded(allocator)).slice()), true };
fn toOwnedSliceImpl(this: String, allocator: std.mem.Allocator) !struct { []u8, AsciiStatus } {
return switch (this.tag) {
.ZigString => .{ try this.value.ZigString.toOwnedSlice(allocator), .unknown },
.WTFStringImpl => blk: {
const utf8_slice = this.value.WTFStringImpl.toUTF8WithoutRef(allocator);
// `utf8_slice.allocator` is either null, or `allocator`.
errdefer utf8_slice.deinit();

const ascii_status: AsciiStatus = if (utf8_slice.allocator.isNull())
.all_ascii // no allocation means the string was 8-bit and all ascii
else if (this.value.WTFStringImpl.is8Bit())
.non_ascii // otherwise the allocator would be null for an 8-bit string
else
.unknown; // string was 16-bit; may or may not be all ascii

const owned_slice = try utf8_slice.cloneIfNeeded(allocator);
// `owned_slice.allocator` is guaranteed to be `allocator`.
break :blk .{ owned_slice.mut(), ascii_status };
},
.StaticZigString => return .{ try this.value.StaticZigString.toOwnedSlice(allocator), false },
else => return .{ &[_]u8{}, false },
}
.StaticZigString => .{
try this.value.StaticZigString.toOwnedSlice(allocator), .unknown,
},
else => return .{ &.{}, .all_ascii }, // trivially all ascii
};
}

pub fn createIfDifferent(other: String, utf8_slice: []const u8) String {
Expand Down Expand Up @@ -1237,6 +1258,7 @@ const std = @import("std");
const bun = @import("bun");
const JSError = bun.JSError;
const OOM = bun.OOM;
const AsciiStatus = bun.strings.AsciiStatus;

const jsc = bun.jsc;
const JSValue = bun.jsc.JSValue;
Expand Down
13 changes: 13 additions & 0 deletions src/string/immutable.zig
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,19 @@ pub const Encoding = enum {
utf16,
};

pub const AsciiStatus = enum {
unknown,
all_ascii,
non_ascii,

pub fn fromBool(is_all_ascii: ?bool) AsciiStatus {
return if (is_all_ascii orelse return .unknown)
.all_ascii
else
.non_ascii;
}
};

/// Returned by classification functions that do not discriminate between utf8 and ascii.
pub const EncodingNonAscii = enum {
utf8,
Expand Down