feat: add io module with File.size async stat and scheduler resume helpers
Introduce a new built-in "io" module exposing a File class with a static size(path) method that performs asynchronous filesystem stat via libuv. The method uses a foreign function startSize_ to initiate the stat request and resumes the calling fiber through the scheduler upon completion. Extend the scheduler with schedulerResumeDouble and schedulerResumeString to support resuming fibers with numeric or string results. Include the generated io.wren.inc source, update the Xcode project to compile io.c and io.wren.inc, register the module in modules.c, and add a test file verifying synchronous-style async size calls and error handling.
This commit is contained in:
@@ -22,6 +22,10 @@
|
||||
29205C9F1AB4E6430073018D /* wren_vm.c in Sources */ = {isa = PBXBuildFile; fileRef = 29205C981AB4E6430073018D /* wren_vm.c */; };
|
||||
29512C811B91F8EB008C10E6 /* libuv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 29512C801B91F8EB008C10E6 /* libuv.a */; };
|
||||
29512C821B91F901008C10E6 /* libuv.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 29512C801B91F8EB008C10E6 /* libuv.a */; };
|
||||
29729F311BA70A620099CA20 /* io.c in Sources */ = {isa = PBXBuildFile; fileRef = 29729F2E1BA70A620099CA20 /* io.c */; };
|
||||
29729F321BA70A620099CA20 /* io.c in Sources */ = {isa = PBXBuildFile; fileRef = 29729F2E1BA70A620099CA20 /* io.c */; };
|
||||
29729F331BA70A620099CA20 /* io.wren.inc in Sources */ = {isa = PBXBuildFile; fileRef = 29729F301BA70A620099CA20 /* io.wren.inc */; };
|
||||
29729F341BA70A620099CA20 /* io.wren.inc in Sources */ = {isa = PBXBuildFile; fileRef = 29729F301BA70A620099CA20 /* io.wren.inc */; };
|
||||
2986F6D71ACF93BA00BCE26C /* wren_primitive.c in Sources */ = {isa = PBXBuildFile; fileRef = 2986F6D51ACF93BA00BCE26C /* wren_primitive.c */; };
|
||||
29C8A9331AB71FFF00DEC81D /* vm.c in Sources */ = {isa = PBXBuildFile; fileRef = 29C8A9311AB71FFF00DEC81D /* vm.c */; };
|
||||
29DE39531AC3A50A00987D41 /* wren_meta.c in Sources */ = {isa = PBXBuildFile; fileRef = 29DE39511AC3A50A00987D41 /* wren_meta.c */; };
|
||||
@@ -75,6 +79,9 @@
|
||||
29512C7F1B91F86E008C10E6 /* api_test */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = api_test; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
29512C801B91F8EB008C10E6 /* libuv.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libuv.a; path = ../../build/libuv.a; sourceTree = "<group>"; };
|
||||
296371B31AC713D000079FDA /* wren_opcodes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wren_opcodes.h; path = ../../src/vm/wren_opcodes.h; sourceTree = "<group>"; };
|
||||
29729F2E1BA70A620099CA20 /* io.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = io.c; path = ../../src/module/io.c; sourceTree = "<group>"; };
|
||||
29729F2F1BA70A620099CA20 /* io.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = io.h; path = ../../src/module/io.h; sourceTree = "<group>"; };
|
||||
29729F301BA70A620099CA20 /* io.wren.inc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.pascal; name = io.wren.inc; path = ../../src/module/io.wren.inc; sourceTree = "<group>"; };
|
||||
2986F6D51ACF93BA00BCE26C /* wren_primitive.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = wren_primitive.c; path = ../../src/vm/wren_primitive.c; sourceTree = "<group>"; };
|
||||
2986F6D61ACF93BA00BCE26C /* wren_primitive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = wren_primitive.h; path = ../../src/vm/wren_primitive.h; sourceTree = "<group>"; };
|
||||
29AB1F061816E3AD004B501E /* wren */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = wren; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
@@ -114,6 +121,9 @@
|
||||
2901D7611B74F3E20083A2C8 /* module */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
29729F2F1BA70A620099CA20 /* io.h */,
|
||||
29729F2E1BA70A620099CA20 /* io.c */,
|
||||
29729F301BA70A620099CA20 /* io.wren.inc */,
|
||||
291647C31BA5EA45006142EE /* scheduler.h */,
|
||||
291647C21BA5EA45006142EE /* scheduler.c */,
|
||||
291647CD1BA5ED26006142EE /* scheduler.wren.inc */,
|
||||
@@ -284,10 +294,12 @@
|
||||
291647C71BA5EC5E006142EE /* modules.c in Sources */,
|
||||
29205C9A1AB4E6430073018D /* wren_core.c in Sources */,
|
||||
2901D7641B74F4050083A2C8 /* timer.c in Sources */,
|
||||
29729F331BA70A620099CA20 /* io.wren.inc in Sources */,
|
||||
29C8A9331AB71FFF00DEC81D /* vm.c in Sources */,
|
||||
291647C41BA5EA45006142EE /* scheduler.c in Sources */,
|
||||
29205C9B1AB4E6430073018D /* wren_debug.c in Sources */,
|
||||
29205C9D1AB4E6430073018D /* wren_utils.c in Sources */,
|
||||
29729F311BA70A620099CA20 /* io.c in Sources */,
|
||||
29205C9E1AB4E6430073018D /* wren_value.c in Sources */,
|
||||
29205C9F1AB4E6430073018D /* wren_vm.c in Sources */,
|
||||
29DE39531AC3A50A00987D41 /* wren_meta.c in Sources */,
|
||||
@@ -299,7 +311,9 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
29729F341BA70A620099CA20 /* io.wren.inc in Sources */,
|
||||
291647C81BA5EC5E006142EE /* modules.c in Sources */,
|
||||
29729F321BA70A620099CA20 /* io.c in Sources */,
|
||||
291647D21BA5ED26006142EE /* timer.wren.inc in Sources */,
|
||||
291647D01BA5ED26006142EE /* scheduler.wren.inc in Sources */,
|
||||
);
|
||||
|
||||
+4
-1
@@ -3,9 +3,11 @@
|
||||
|
||||
#include "modules.h"
|
||||
|
||||
#include "io.wren.inc"
|
||||
#include "scheduler.wren.inc"
|
||||
#include "timer.wren.inc"
|
||||
|
||||
#include "io.h"
|
||||
#include "scheduler.h"
|
||||
#include "timer.h"
|
||||
|
||||
@@ -30,8 +32,9 @@ typedef struct
|
||||
// The array of built-in modules.
|
||||
static BuiltInModule modules[] =
|
||||
{
|
||||
{"io", &ioModuleSource, ioBindForeign, NULL},
|
||||
{"scheduler", &schedulerModuleSource, schedulerBindForeign, NULL},
|
||||
{"timer", &timerModuleSource, timerBindForeign, NULL},
|
||||
{"timer", &timerModuleSource, timerBindForeign, NULL},
|
||||
|
||||
// Sentinel marking the end of the list.
|
||||
{NULL, NULL, NULL, NULL}
|
||||
|
||||
+1
-1
@@ -2,8 +2,8 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "modules.h"
|
||||
#include "vm.h"
|
||||
#include "scheduler.h"
|
||||
#include "vm.h"
|
||||
|
||||
#define MAX_LINE_LENGTH 1024 // TODO: Something less arbitrary.
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "uv.h"
|
||||
|
||||
#include "io.h"
|
||||
#include "scheduler.h"
|
||||
#include "vm.h"
|
||||
#include "wren.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
// Called by libuv when the stat call for size completes.
|
||||
static void sizeCallback(uv_fs_t* request)
|
||||
{
|
||||
WrenValue* fiber = (WrenValue*)request->data;
|
||||
|
||||
if (request->result != 0)
|
||||
{
|
||||
schedulerResumeString(fiber, uv_strerror((int)request->result));
|
||||
uv_fs_req_cleanup(request);
|
||||
return;
|
||||
}
|
||||
|
||||
double size = (double)request->statbuf.st_size;
|
||||
uv_fs_req_cleanup(request);
|
||||
|
||||
schedulerResumeDouble(fiber, size);
|
||||
}
|
||||
|
||||
static void startSize(WrenVM* vm)
|
||||
{
|
||||
const char* path = wrenGetArgumentString(vm, 1);
|
||||
WrenValue* fiber = wrenGetArgumentValue(vm, 2);
|
||||
|
||||
// Store the fiber to resume when the request completes.
|
||||
uv_fs_t* request = (uv_fs_t*)malloc(sizeof(uv_fs_t));
|
||||
request->data = fiber;
|
||||
|
||||
uv_fs_stat(getLoop(), request, path, sizeCallback);
|
||||
}
|
||||
|
||||
WrenForeignMethodFn ioBindForeign(
|
||||
WrenVM* vm, const char* className, bool isStatic, const char* signature)
|
||||
{
|
||||
if (strcmp(className, "File") != 0) return NULL;
|
||||
|
||||
if (isStatic && strcmp(signature, "startSize_(_,_)") == 0) return startSize;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef io_h
|
||||
#define io_h
|
||||
|
||||
#include "wren.h"
|
||||
|
||||
WrenForeignMethodFn ioBindForeign(
|
||||
WrenVM* vm, const char* className, bool isStatic, const char* signature);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
import "scheduler" for Scheduler
|
||||
|
||||
class File {
|
||||
static size(path) {
|
||||
if (!(path is String)) Fiber.abort("Path must be a string.")
|
||||
|
||||
startSize_(path, Fiber.current)
|
||||
var result = Scheduler.runNextScheduled_()
|
||||
if (result is String) Fiber.abort(result)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
foreign static startSize_(path, fiber)
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Generated automatically from src/module/io.wren. Do not edit.
|
||||
static const char* ioModuleSource =
|
||||
"import \"scheduler\" for Scheduler\n"
|
||||
"\n"
|
||||
"class File {\n"
|
||||
" static size(path) {\n"
|
||||
" if (!(path is String)) Fiber.abort(\"Path must be a string.\")\n"
|
||||
"\n"
|
||||
" startSize_(path, Fiber.current)\n"
|
||||
" var result = Scheduler.runNextScheduled_()\n"
|
||||
" if (result is String) Fiber.abort(result)\n"
|
||||
"\n"
|
||||
" return result\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" foreign static startSize_(path, fiber)\n"
|
||||
"}\n";
|
||||
@@ -35,6 +35,18 @@ void schedulerResume(WrenValue* fiber)
|
||||
wrenReleaseValue(getVM(), fiber);
|
||||
}
|
||||
|
||||
void schedulerResumeDouble(WrenValue* fiber, double value)
|
||||
{
|
||||
wrenCall(getVM(), resumeWithArg, NULL, "vd", fiber, value);
|
||||
wrenReleaseValue(getVM(), fiber);
|
||||
}
|
||||
|
||||
void schedulerResumeString(WrenValue* fiber, const char* text)
|
||||
{
|
||||
wrenCall(getVM(), resumeWithArg, NULL, "vs", fiber, text);
|
||||
wrenReleaseValue(getVM(), fiber);
|
||||
}
|
||||
|
||||
void schedulerReleaseMethods()
|
||||
{
|
||||
if (resume != NULL) wrenReleaseValue(getVM(), resume);
|
||||
|
||||
@@ -7,6 +7,8 @@ WrenForeignMethodFn schedulerBindForeign(
|
||||
WrenVM* vm, const char* className, bool isStatic, const char* signature);
|
||||
|
||||
void schedulerResume(WrenValue* fiber);
|
||||
void schedulerResumeDouble(WrenValue* fiber, double value);
|
||||
void schedulerResumeString(WrenValue* fiber, const char* text);
|
||||
|
||||
void schedulerReleaseMethods();
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import "io" for File
|
||||
import "scheduler" for Scheduler
|
||||
|
||||
System.print(File.size("test/io/file/size.wren")) // expect: 401
|
||||
|
||||
// Runs asynchronously.
|
||||
Scheduler.add {
|
||||
System.print("async")
|
||||
}
|
||||
|
||||
System.print(File.size("test/io/file/size.wren"))
|
||||
// expect: async
|
||||
// expect: 401
|
||||
|
||||
var error = Fiber.new {
|
||||
System.print(File.size("nonexistent"))
|
||||
}.try()
|
||||
System.print(error) // expect: no such file or directory
|
||||
Reference in New Issue
Block a user