feat: add optional offset parameter to File.readBytes method
Extend File.readBytes with a second overload accepting an offset argument, allowing reads to start at any byte position from the beginning of the file. The existing single-argument variant now delegates to the new two-argument version with offset 0. Validation for the offset parameter mirrors the existing count checks, aborting on non-numeric, non-integer, or negative values. The underlying C implementation passes the offset directly to uv_fs_read, replacing the previous hardcoded zero. Documentation in the io module markdown is updated with usage examples for both signatures, and the old TODO comment about missing offset support is removed. New test files cover offset-based reads, edge cases (zero offset, past-end offset, zero count with offset), and error conditions for invalid offset arguments.
This commit is contained in:
+6
-4
@@ -228,12 +228,13 @@ static void fileReadBytesCallback(uv_fs_t* request)
|
||||
|
||||
FileRequestData* data = (FileRequestData*)request->data;
|
||||
uv_buf_t buffer = data->buffer;
|
||||
size_t count = request->result;
|
||||
|
||||
// TODO: Having to copy the bytes here is a drag. It would be good if Wren's
|
||||
// embedding API supported a way to *give* it bytes that were previously
|
||||
// allocated using Wren's own allocator.
|
||||
schedulerResume(freeRequest(request), true);
|
||||
wrenSetSlotBytes(getVM(), 2, buffer.base, buffer.len);
|
||||
wrenSetSlotBytes(getVM(), 2, buffer.base, count);
|
||||
schedulerFinishResume();
|
||||
|
||||
// TODO: Likewise, freeing this after we resume is lame.
|
||||
@@ -242,19 +243,20 @@ static void fileReadBytesCallback(uv_fs_t* request)
|
||||
|
||||
void fileReadBytes(WrenVM* vm)
|
||||
{
|
||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 2));
|
||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 3));
|
||||
|
||||
int fd = *(int*)wrenGetSlotForeign(vm, 0);
|
||||
// TODO: Assert fd != -1.
|
||||
|
||||
FileRequestData* data = (FileRequestData*)request->data;
|
||||
size_t length = (size_t)wrenGetSlotDouble(vm, 1);
|
||||
size_t offset = (size_t)wrenGetSlotDouble(vm, 2);
|
||||
|
||||
data->buffer.len = length;
|
||||
data->buffer.base = (char*)malloc(length);
|
||||
|
||||
// TODO: Allow passing in offset.
|
||||
uv_fs_read(getLoop(), request, fd, &data->buffer, 1, 0, fileReadBytesCallback);
|
||||
uv_fs_read(getLoop(), request, fd, &data->buffer, 1, offset,
|
||||
fileReadBytesCallback);
|
||||
}
|
||||
|
||||
void fileSize(WrenVM* vm)
|
||||
|
||||
+9
-3
@@ -62,13 +62,19 @@ foreign class File {
|
||||
return Scheduler.runNextScheduled_()
|
||||
}
|
||||
|
||||
readBytes(count) {
|
||||
readBytes(count) { readBytes(count, 0) }
|
||||
|
||||
readBytes(count, offset) {
|
||||
if (!isOpen) Fiber.abort("File is not open.")
|
||||
if (!(count is Num)) Fiber.abort("Count must be an integer.")
|
||||
if (!count.isInteger) Fiber.abort("Count must be an integer.")
|
||||
if (count < 0) Fiber.abort("Count cannot be negative.")
|
||||
|
||||
readBytes_(count, Fiber.current)
|
||||
if (!(offset is Num)) Fiber.abort("Offset must be an integer.")
|
||||
if (!offset.isInteger) Fiber.abort("Offset must be an integer.")
|
||||
if (offset < 0) Fiber.abort("Offset cannot be negative.")
|
||||
|
||||
readBytes_(count, offset, Fiber.current)
|
||||
return Scheduler.runNextScheduled_()
|
||||
}
|
||||
|
||||
@@ -76,7 +82,7 @@ foreign class File {
|
||||
foreign static sizePath_(path, fiber)
|
||||
|
||||
foreign close_(fiber)
|
||||
foreign readBytes_(count, fiber)
|
||||
foreign readBytes_(count, start, fiber)
|
||||
foreign size_(fiber)
|
||||
}
|
||||
|
||||
|
||||
+11
-4
@@ -53,6 +53,8 @@ static const char* ioModuleSource =
|
||||
" Scheduler.runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign descriptor\n"
|
||||
"\n"
|
||||
" isOpen { descriptor != -1 }\n"
|
||||
"\n"
|
||||
" size {\n"
|
||||
@@ -62,13 +64,19 @@ static const char* ioModuleSource =
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" readBytes(count) {\n"
|
||||
" readBytes(count) { readBytes(count, 0) }\n"
|
||||
"\n"
|
||||
" readBytes(count, offset) {\n"
|
||||
" if (!isOpen) Fiber.abort(\"File is not open.\")\n"
|
||||
" if (!(count is Num)) Fiber.abort(\"Count must be an integer.\")\n"
|
||||
" if (!count.isInteger) Fiber.abort(\"Count must be an integer.\")\n"
|
||||
" if (count < 0) Fiber.abort(\"Count cannot be negative.\")\n"
|
||||
"\n"
|
||||
" readBytes_(count, Fiber.current)\n"
|
||||
" if (!(offset is Num)) Fiber.abort(\"Offset must be an integer.\")\n"
|
||||
" if (!offset.isInteger) Fiber.abort(\"Offset must be an integer.\")\n"
|
||||
" if (offset < 0) Fiber.abort(\"Offset cannot be negative.\")\n"
|
||||
"\n"
|
||||
" readBytes_(count, offset, Fiber.current)\n"
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
@@ -76,8 +84,7 @@ static const char* ioModuleSource =
|
||||
" foreign static sizePath_(path, fiber)\n"
|
||||
"\n"
|
||||
" foreign close_(fiber)\n"
|
||||
" foreign descriptor\n"
|
||||
" foreign readBytes_(count, fiber)\n"
|
||||
" foreign readBytes_(count, start, fiber)\n"
|
||||
" foreign size_(fiber)\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
|
||||
Reference in New Issue
Block a user