mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-14 15:28:57 +00:00
port remaining blob functionality
This commit is contained in:
@@ -196,8 +196,8 @@ pub fn blob(self: *Factory, child: anytype) !*@TypeOf(child) {
|
||||
const blob_ptr = chain.get(0);
|
||||
blob_ptr.* = .{
|
||||
._type = unionInit(Blob.Type, chain.get(1)),
|
||||
.slice = "",
|
||||
.mime = "",
|
||||
._slice = "",
|
||||
._mime = "",
|
||||
};
|
||||
chain.setLeaf(1, child);
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<head id="the_head">
|
||||
<title>Test Document Title</title>
|
||||
<script src="./testing.js"></script>
|
||||
</head>
|
||||
<meta charset="UTF-8">
|
||||
<script src="./testing.js"></script>
|
||||
|
||||
<script id=basic>
|
||||
{
|
||||
@@ -13,7 +11,7 @@
|
||||
const expected = parts.join("");
|
||||
testing.expectEqual(expected.length, blob.size);
|
||||
testing.expectEqual("text/html", blob.type);
|
||||
testing.async(blob.text(), result => testing.expectEqual(expected, result));
|
||||
testing.async(async () => { testing.expectEqual(expected, await blob.text()) });
|
||||
}
|
||||
|
||||
{
|
||||
@@ -23,34 +21,7 @@
|
||||
|
||||
const expected = "\nhello\n\nwor\nld";
|
||||
testing.expectEqual(expected.length, blob.size);
|
||||
testing.async(blob.text(), result => testing.expectEqual(expected, result));
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=slice>
|
||||
{
|
||||
const parts = ["la", "symphonie", "des", "éclairs"];
|
||||
const blob = new Blob(parts);
|
||||
|
||||
let temp = blob.slice(0);
|
||||
testing.expectEqual(blob.size, temp.size);
|
||||
testing.async(temp.text(), result => {
|
||||
testing.expectEqual("lasymphoniedeséclairs", result);
|
||||
});
|
||||
|
||||
temp = blob.slice(-4, -2, "custom");
|
||||
testing.expectEqual(2, temp.size);
|
||||
testing.expectEqual("custom", temp.type);
|
||||
testing.async(temp.text(), result => testing.expectEqual("ai", result));
|
||||
|
||||
temp = blob.slice(14);
|
||||
testing.expectEqual(8, temp.size);
|
||||
testing.async(temp.text(), result => testing.expectEqual("éclairs", result));
|
||||
|
||||
temp = blob.slice(6, -10, "text/eclair");
|
||||
testing.expectEqual(6, temp.size);
|
||||
testing.expectEqual("text/eclair", temp.type);
|
||||
testing.async(temp.text(), result => testing.expectEqual("honied", result));
|
||||
testing.async(async () => { testing.expectEqual(expected, await blob.text()) });
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -60,10 +31,11 @@
|
||||
const parts = ["light ", "panda ", "rocks ", "!"];
|
||||
const blob = new Blob(parts);
|
||||
|
||||
testing.async(blob.bytes(), result => {
|
||||
testing.async(async() => {
|
||||
const expected = new Uint8Array([108, 105, 103, 104, 116, 32, 112, 97,
|
||||
110, 100, 97, 32, 114, 111, 99, 107, 115,
|
||||
32, 33]);
|
||||
const result = await blob.bytes();
|
||||
testing.expectEqual(true, result instanceof Uint8Array);
|
||||
testing.expectEqual(expected, result);
|
||||
});
|
||||
@@ -81,7 +53,7 @@
|
||||
const blob = new Blob(parts, { type: "text/html", endings: "native" });
|
||||
testing.expectEqual(161, blob.size);
|
||||
testing.expectEqual("text/html", blob.type);
|
||||
testing.async(blob.bytes(), result => {
|
||||
testing.async(async() => {
|
||||
const expected = new Uint8Array([10, 84, 104, 101, 32, 111, 112, 101, 110,
|
||||
101, 100, 32, 112, 97, 99, 107, 97, 103,
|
||||
101, 10, 111, 102, 32, 112, 111, 116, 97,
|
||||
@@ -100,8 +72,65 @@
|
||||
10, 10, 116, 111, 32, 115, 111, 108, 118, 101,
|
||||
32, 116, 104, 101, 32, 10, 99, 114, 105, 109,
|
||||
101, 46, 10]);
|
||||
const result = await blob.bytes();
|
||||
testing.expectEqual(true, result instanceof Uint8Array);
|
||||
testing.expectEqual(expected, result);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=stream>
|
||||
{
|
||||
const parts = ["may", "thy", "knife", "chip", "and", "shatter"];
|
||||
const blob = new Blob(parts);
|
||||
const reader = blob.stream().getReader();
|
||||
|
||||
testing.async(async () => {
|
||||
const {done: done, value: value} = await reader.read()
|
||||
const expected = new Uint8Array([109, 97, 121, 116, 104, 121, 107, 110,
|
||||
105, 102, 101, 99, 104, 105, 112, 97,
|
||||
110, 100, 115, 104, 97, 116, 116, 101,
|
||||
114]);
|
||||
testing.expectEqual(false, done);
|
||||
testing.expectEqual(true, value instanceof Uint8Array);
|
||||
testing.expectEqual(expected, value);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=slice>
|
||||
{
|
||||
const parts = ["la", "symphonie", "des", "éclairs"];
|
||||
const blob = new Blob(parts);
|
||||
testing.async(async () => {
|
||||
const result = await blob.arrayBuffer();
|
||||
testing.expectEqual(true, result instanceof ArrayBuffer)
|
||||
});
|
||||
|
||||
let temp = blob.slice(0);
|
||||
testing.expectEqual(blob.size, temp.size);
|
||||
testing.async(async () => {
|
||||
testing.expectEqual("lasymphoniedeséclairs", await temp.text());
|
||||
});
|
||||
|
||||
temp = blob.slice(-4, -2, "custom");
|
||||
testing.expectEqual(2, temp.size);
|
||||
testing.expectEqual("custom", temp.type);
|
||||
testing.async(async () => {
|
||||
testing.expectEqual("ai", await temp.text());
|
||||
});
|
||||
|
||||
temp = blob.slice(14);
|
||||
testing.expectEqual(8, temp.size);
|
||||
testing.async(async () => {
|
||||
testing.expectEqual("éclairs", await temp.text());
|
||||
});
|
||||
|
||||
temp = blob.slice(6, -10, "text/eclair");
|
||||
testing.expectEqual(6, temp.size);
|
||||
testing.expectEqual("text/eclair", temp.type);
|
||||
testing.async(async () => {
|
||||
testing.expectEqual("honied", await temp.text());
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -27,14 +27,15 @@ const Page = @import("../Page.zig");
|
||||
const Blob = @This();
|
||||
|
||||
const _prototype_root = true;
|
||||
|
||||
_type: Type,
|
||||
|
||||
/// Immutable slice of blob.
|
||||
/// Note that another blob may hold a pointer/slice to this,
|
||||
/// so its better to leave the deallocation of it to arena allocator.
|
||||
slice: []const u8,
|
||||
_slice: []const u8,
|
||||
/// MIME attached to blob. Can be an empty string.
|
||||
mime: []const u8,
|
||||
_mime: []const u8,
|
||||
|
||||
pub const Type = union(enum) {
|
||||
generic,
|
||||
@@ -66,7 +67,7 @@ pub fn init(
|
||||
break :blk try page.arena.dupe(u8, t);
|
||||
};
|
||||
|
||||
const slice = blk: {
|
||||
const data = blk: {
|
||||
if (maybe_blob_parts) |blob_parts| {
|
||||
var w: Writer.Allocating = .init(page.arena);
|
||||
const use_native_endings = std.mem.eql(u8, options.endings, "native");
|
||||
@@ -80,8 +81,8 @@ pub fn init(
|
||||
|
||||
return page._factory.create(Blob{
|
||||
._type = .generic,
|
||||
.slice = slice,
|
||||
.mime = mime,
|
||||
._slice = data,
|
||||
._mime = mime,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -147,8 +148,8 @@ fn writeBlobParts(
|
||||
while (end + vector_len <= part.len) : (end += vector_len) {
|
||||
const cr: Vec = @splat('\r');
|
||||
// Load chunk as vectors.
|
||||
const slice = part[end..][0..vector_len];
|
||||
const chunk: Vec = slice.*;
|
||||
const data = part[end..][0..vector_len];
|
||||
const chunk: Vec = data.*;
|
||||
// Look for CR.
|
||||
const match = chunk == cr;
|
||||
|
||||
@@ -160,16 +161,16 @@ fn writeBlobParts(
|
||||
var iter = bitset.iterator(.{});
|
||||
var relative_start: usize = 0;
|
||||
while (iter.next()) |index| {
|
||||
_ = try writer.writeVec(&.{ slice[relative_start..index], "\n" });
|
||||
_ = try writer.writeVec(&.{ data[relative_start..index], "\n" });
|
||||
|
||||
if (index + 1 != slice.len and slice[index + 1] == '\n') {
|
||||
if (index + 1 != data.len and data[index + 1] == '\n') {
|
||||
relative_start = index + 2;
|
||||
} else {
|
||||
relative_start = index + 1;
|
||||
}
|
||||
}
|
||||
|
||||
_ = try writer.writeVec(&.{slice[relative_start..]});
|
||||
_ = try writer.writeVec(&.{data[relative_start..]});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,16 +205,21 @@ fn writeBlobParts(
|
||||
|
||||
/// Returns a Promise that resolves with the contents of the blob
|
||||
/// as binary data contained in an ArrayBuffer.
|
||||
//pub fn arrayBuffer(self: *const Blob, page: *Page) !js.Promise {
|
||||
// return page.js.resolvePromise(js.ArrayBuffer{ .values = self.slice });
|
||||
//}
|
||||
pub fn arrayBuffer(self: *const Blob, page: *Page) !js.Promise {
|
||||
return page.js.resolvePromise(js.ArrayBuffer{ .values = self._slice });
|
||||
}
|
||||
|
||||
// TODO: Implement `stream`; requires `ReadableStream`.
|
||||
const ReadableStream = @import("streams/ReadableStream.zig");
|
||||
/// Returns a ReadableStream which upon reading returns the data
|
||||
/// contained within the Blob.
|
||||
pub fn stream(self: *const Blob, page: *Page) !*ReadableStream {
|
||||
return ReadableStream.initWithData(self._slice, page);
|
||||
}
|
||||
|
||||
/// Returns a Promise that resolves with a string containing
|
||||
/// the contents of the blob, interpreted as UTF-8.
|
||||
pub fn text(self: *const Blob, page: *Page) !js.Promise {
|
||||
return page.js.resolvePromise(self.slice);
|
||||
return page.js.resolvePromise(self._slice);
|
||||
}
|
||||
|
||||
/// Extension to Blob; works on Firefox and Safari.
|
||||
@@ -221,12 +227,12 @@ pub fn text(self: *const Blob, page: *Page) !js.Promise {
|
||||
/// Returns a Promise that resolves with a Uint8Array containing
|
||||
/// the contents of the blob as an array of bytes.
|
||||
pub fn bytes(self: *const Blob, page: *Page) !js.Promise {
|
||||
return page.js.resolvePromise(js.TypedArray(u8){ .values = self.slice });
|
||||
return page.js.resolvePromise(js.TypedArray(u8){ .values = self._slice });
|
||||
}
|
||||
|
||||
/// Returns a new Blob object which contains data
|
||||
/// from a subset of the blob on which it's called.
|
||||
pub fn getSlice(
|
||||
pub fn slice(
|
||||
self: *const Blob,
|
||||
maybe_start: ?i32,
|
||||
maybe_end: ?i32,
|
||||
@@ -239,56 +245,56 @@ pub fn getSlice(
|
||||
break :blk "";
|
||||
}
|
||||
|
||||
break :blk try page.arena.dupe(u8, content_type);
|
||||
break :blk try page.dupeString(content_type);
|
||||
}
|
||||
|
||||
break :blk "";
|
||||
};
|
||||
|
||||
const slice = self.slice;
|
||||
const data = self._slice;
|
||||
if (maybe_start) |_start| {
|
||||
const start = blk: {
|
||||
if (_start < 0) {
|
||||
break :blk slice.len -| @abs(_start);
|
||||
break :blk data.len -| @abs(_start);
|
||||
}
|
||||
|
||||
break :blk @min(slice.len, @as(u31, @intCast(_start)));
|
||||
break :blk @min(data.len, @as(u31, @intCast(_start)));
|
||||
};
|
||||
|
||||
const end: usize = blk: {
|
||||
if (maybe_end) |_end| {
|
||||
if (_end < 0) {
|
||||
break :blk @max(start, slice.len -| @abs(_end));
|
||||
break :blk @max(start, data.len -| @abs(_end));
|
||||
}
|
||||
|
||||
break :blk @min(slice.len, @max(start, @as(u31, @intCast(_end))));
|
||||
break :blk @min(data.len, @max(start, @as(u31, @intCast(_end))));
|
||||
}
|
||||
|
||||
break :blk slice.len;
|
||||
break :blk data.len;
|
||||
};
|
||||
|
||||
return page._factory.create(Blob{
|
||||
._type = .generic,
|
||||
.slice = slice[start..end],
|
||||
.mime = mime,
|
||||
._slice = data[start..end],
|
||||
._mime = mime,
|
||||
});
|
||||
}
|
||||
|
||||
return page._factory.create(Blob{
|
||||
._type = .generic,
|
||||
.slice = slice,
|
||||
.mime = mime,
|
||||
._slice = data,
|
||||
._mime = mime,
|
||||
});
|
||||
}
|
||||
|
||||
/// Returns the size of the Blob in bytes.
|
||||
pub fn getSize(self: *const Blob) usize {
|
||||
return self.slice.len;
|
||||
return self._slice.len;
|
||||
}
|
||||
|
||||
/// Returns the type of Blob; likely a MIME type, yet anything can be given.
|
||||
pub fn getType(self: *const Blob) []const u8 {
|
||||
return self.mime;
|
||||
return self._mime;
|
||||
}
|
||||
|
||||
pub const JsApi = struct {
|
||||
@@ -303,9 +309,11 @@ pub const JsApi = struct {
|
||||
pub const constructor = bridge.constructor(Blob.init, .{});
|
||||
pub const text = bridge.function(Blob.text, .{});
|
||||
pub const bytes = bridge.function(Blob.bytes, .{});
|
||||
pub const slice = bridge.function(Blob.getSlice, .{});
|
||||
pub const slice = bridge.function(Blob.slice, .{});
|
||||
pub const size = bridge.accessor(Blob.getSize, null, .{});
|
||||
pub const @"type" = bridge.accessor(Blob.getType, null, .{});
|
||||
pub const stream = bridge.function(Blob.stream, .{});
|
||||
pub const arrayBuffer = bridge.function(Blob.arrayBuffer, .{});
|
||||
};
|
||||
|
||||
const testing = @import("../../testing.zig");
|
||||
|
||||
Reference in New Issue
Block a user