feat: add File.stat() method and Stat class for filesystem metadata queries
Implement asynchronous stat() on File class returning a new Stat object with device, inode, mode, linkCount, user, group, specialDevice, size, blockSize, and blockCount fields populated from libuv uv_fs_stat callback. Register foreign method statPath_ in module registry, bump MAX_METHODS_PER_CLASS to 10, add Stat class to io.wren with indexed field accessors, update documentation index with Stat page, and include test coverage for stat on existing file and nonexistent path.
This commit is contained in:
@@ -188,6 +188,62 @@ void fileSizePath(WrenVM* vm)
|
||||
uv_fs_stat(getLoop(), request, path, fileSizeCallback);
|
||||
}
|
||||
|
||||
// Called by libuv when the stat call completes.
|
||||
static void fileStatPathCallback(uv_fs_t* request)
|
||||
{
|
||||
if (handleRequestError(request)) return;
|
||||
|
||||
WrenVM* vm = getVM();
|
||||
wrenEnsureSlots(vm, 4);
|
||||
wrenSetSlotNewList(vm, 2);
|
||||
|
||||
wrenSetSlotDouble(vm, 3, (double)request->statbuf.st_dev);
|
||||
wrenInsertInList(vm, 2, -1, 3);
|
||||
|
||||
wrenSetSlotDouble(vm, 3, (double)request->statbuf.st_ino);
|
||||
wrenInsertInList(vm, 2, -1, 3);
|
||||
|
||||
wrenSetSlotDouble(vm, 3, (double)request->statbuf.st_mode);
|
||||
wrenInsertInList(vm, 2, -1, 3);
|
||||
|
||||
wrenSetSlotDouble(vm, 3, (double)request->statbuf.st_nlink);
|
||||
wrenInsertInList(vm, 2, -1, 3);
|
||||
|
||||
wrenSetSlotDouble(vm, 3, (double)request->statbuf.st_uid);
|
||||
wrenInsertInList(vm, 2, -1, 3);
|
||||
|
||||
wrenSetSlotDouble(vm, 3, (double)request->statbuf.st_gid);
|
||||
wrenInsertInList(vm, 2, -1, 3);
|
||||
|
||||
wrenSetSlotDouble(vm, 3, (double)request->statbuf.st_rdev);
|
||||
wrenInsertInList(vm, 2, -1, 3);
|
||||
|
||||
wrenSetSlotDouble(vm, 3, (double)request->statbuf.st_size);
|
||||
wrenInsertInList(vm, 2, -1, 3);
|
||||
|
||||
wrenSetSlotDouble(vm, 3, (double)request->statbuf.st_blksize);
|
||||
wrenInsertInList(vm, 2, -1, 3);
|
||||
|
||||
wrenSetSlotDouble(vm, 3, (double)request->statbuf.st_blocks);
|
||||
wrenInsertInList(vm, 2, -1, 3);
|
||||
|
||||
// TODO: Include access, modification, and change times once we figure out
|
||||
// how we want to represent it.
|
||||
// time_t st_atime; /* time of last access */
|
||||
// time_t st_mtime; /* time of last modification */
|
||||
// time_t st_ctime; /* time of last status change */
|
||||
|
||||
schedulerResume(freeRequest(request), true);
|
||||
schedulerFinishResume();
|
||||
}
|
||||
|
||||
void fileStatPath(WrenVM* vm)
|
||||
{
|
||||
const char* path = wrenGetSlotString(vm, 1);
|
||||
uv_fs_t* request = createRequest(wrenGetSlotValue(vm, 2));
|
||||
uv_fs_stat(getLoop(), request, path, fileStatPathCallback);
|
||||
}
|
||||
|
||||
static void fileCloseCallback(uv_fs_t* request)
|
||||
{
|
||||
if (handleRequestError(request)) return;
|
||||
|
||||
@@ -44,6 +44,13 @@ foreign class File {
|
||||
return Scheduler.runNextScheduled_()
|
||||
}
|
||||
|
||||
static stat(path) {
|
||||
if (!(path is String)) Fiber.abort("Path must be a string.")
|
||||
|
||||
statPath_(path, Fiber.current)
|
||||
return Stat.new_(Scheduler.runNextScheduled_())
|
||||
}
|
||||
|
||||
construct new_(fd) {}
|
||||
|
||||
close() {
|
||||
@@ -80,12 +87,30 @@ foreign class File {
|
||||
|
||||
foreign static open_(path, fiber)
|
||||
foreign static sizePath_(path, fiber)
|
||||
foreign static statPath_(path, fiber)
|
||||
|
||||
foreign close_(fiber)
|
||||
foreign readBytes_(count, start, fiber)
|
||||
foreign size_(fiber)
|
||||
}
|
||||
|
||||
class Stat {
|
||||
construct new_(fields) {
|
||||
_fields = fields
|
||||
}
|
||||
|
||||
device { _fields[0] }
|
||||
inode { _fields[1] }
|
||||
mode { _fields[2] }
|
||||
linkCount { _fields[3] }
|
||||
user { _fields[4] }
|
||||
group { _fields[5] }
|
||||
specialDevice { _fields[6] }
|
||||
size { _fields[7] }
|
||||
blockSize { _fields[8] }
|
||||
blockCount { _fields[9] }
|
||||
}
|
||||
|
||||
class Stdin {
|
||||
static readLine() {
|
||||
if (__isClosed == true) {
|
||||
|
||||
@@ -46,6 +46,13 @@ static const char* ioModuleSource =
|
||||
" return Scheduler.runNextScheduled_()\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" static stat(path) {\n"
|
||||
" if (!(path is String)) Fiber.abort(\"Path must be a string.\")\n"
|
||||
"\n"
|
||||
" statPath_(path, Fiber.current)\n"
|
||||
" return Stat.new_(Scheduler.runNextScheduled_())\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" construct new_(fd) {}\n"
|
||||
"\n"
|
||||
" close() {\n"
|
||||
@@ -82,12 +89,30 @@ static const char* ioModuleSource =
|
||||
"\n"
|
||||
" foreign static open_(path, fiber)\n"
|
||||
" foreign static sizePath_(path, fiber)\n"
|
||||
" foreign static statPath_(path, fiber)\n"
|
||||
"\n"
|
||||
" foreign close_(fiber)\n"
|
||||
" foreign readBytes_(count, start, fiber)\n"
|
||||
" foreign size_(fiber)\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class Stat {\n"
|
||||
" construct new_(fields) {\n"
|
||||
" _fields = fields\n"
|
||||
" }\n"
|
||||
"\n"
|
||||
" device { _fields[0] }\n"
|
||||
" inode { _fields[1] }\n"
|
||||
" mode { _fields[2] }\n"
|
||||
" linkCount { _fields[3] }\n"
|
||||
" user { _fields[4] }\n"
|
||||
" group { _fields[5] }\n"
|
||||
" specialDevice { _fields[6] }\n"
|
||||
" size { _fields[7] }\n"
|
||||
" blockSize { _fields[8] }\n"
|
||||
" blockCount { _fields[9] }\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"class Stdin {\n"
|
||||
" static readLine() {\n"
|
||||
" if (__isClosed == true) {\n"
|
||||
|
||||
Reference in New Issue
Block a user