File interface - chung-leong/zigar GitHub Wiki
Interface implemented by objects representing files in the virtual file system. It contains methods for reading, writing, and changing file position. Methods can be either synchronous or asynchronous, with the latter case limiting operations to worker threads.
Objects implementing the file interface are used in the following contexts:
- As an argument of a Zig function expecting a std.fs.File
- As an argument of a Zig function expecting a std.io.AnyReader or std.io.AnyWriter
- As the return value of an 'open' event listener
- As the second argument of __zigar.redirect()
The following objects are automatically provided with file interfaces:
-
null(sync, read-write) -
string(sync, read-only, seekable) -
array(sync, write-only) -
Uint8Array(sync, read-write, seekable) -
Blob(async, read-only, seekable) -
ReadableStreamDefaultReader(async, read-only) -
ReadableStreamBYOBReader(async, read-only) -
WritableStreamDefaultWriter(async, write-only)
Example 1:
const std = @import("std");
pub fn print(file: std.fs.File) !void {
const stdout = std.io.getStdOut();
var buffer: [1024]u8 = undefined;
while (true) {
const len = try file.read(&buffer);
if (len == 0) break;
_ = try stdout.write(buffer[0..len]);
}
}import { print } from './file-example-1.zig';
// using a string as a file
print('Hello world\n'.repeat(5));Hello world
Hello world
Hello world
Hello world
Hello world
Zigar attaches a close method to the original object that allows you to close the file descriptor
created during the conversion to std.fs.File from JavaScript. The above example passes a string
so we weren't able to do that. Making the string an object fixes this issue:
import { print } from './file-example-1.zig';
const s = Object('Hello world\n'.repeat(5));
print(s);
s.close();When multiple descriptors are opened to the same object, a call to close() closes them all.
Of course, you can also choose to close the file on the Zig side.
Example 2:
const std = @import("std");
pub fn print(text: []const u8) void {
std.debug.print("{s}\n", .{text});
}import { __zigar, print } from './file-example-2.zig';
print('hello');
// redirecting stderr to null
const stderr = __zigar.redirect('stderr', null);
print('world');
// restoring stderr
__zigar.redirect('stderr', stderr);
print('hello');hello
hello
Example 3:
const std = @import("std");
const zigar = @import("zigar");
var gpa = std.heap.DebugAllocator(.{}).init;
var work_queue: zigar.thread.WorkQueue(worker) = .{};
pub fn startup() !void {
try work_queue.init(.{
.allocator = gpa.allocator(),
.n_jobs = 1,
});
}
pub fn shutdown(promise: zigar.function.Promise(void)) void {
return work_queue.deinitAsync(promise);
}
pub const print = work_queue.promisify(worker.print);
const worker = struct {
pub fn print() !void {
var file = try std.fs.openFileAbsolute("/index.html", .{});
defer file.close();
const stdout = std.io.getStdOut();
var buffer: [1024]u8 = undefined;
while (true) {
const len = try file.read(&buffer);
if (len == 0) break;
_ = try stdout.write(buffer[0..len]);
}
}
};import { __zigar, print, shutdown, startup } from './file-example-3.zig';
__zigar.on('open', async (evt) => {
// use content from a website
console.log(`${evt.path}:`);
const response = await fetch(`https://example.net/${evt.path}`);
return response.body.getReader();
})
startup();
try {
await print();
} finally {
await shutdown();
}index.html:
<!doctype html><html lang="en"><head><title>Example Domain</title><meta name="viewport" content="width=device-width, initial-scale=1"><style>body{background:#eee;width:60vw;margin:15vh auto;font-family:system-ui,sans-serif}h1{font-size:1.5em}div{opacity:0.8}a:link,a:visited{color:#348}</style><body><div><h1>Example Domain</h1><p>This domain is for use in documentation examples without needing permission. Avoid use in operations.<p><a href="https://iana.org/domains/example">Learn more</a></div></body></html>
If the built-in support is unable to meet your needs, you can define a stream class of your own. It should have the following methods:
-
read(len)
Read up tolenbytes from the stream. The return value is expected to be aUint8Array. -
write(bytes)
Writebytesoperation to stream.bytesis always aUint8Array.
The following methods must be present for the file to be seekable:
-
seek(offset, whence)
Change file position.whencecan be 0, 1, or 2 (SET, CUR, END). -
tell()
Return the file position.
The following methods must be present to enable non-blocking mode:
-
poll()
Return the number of bytes that are immediately readable/writable or a promise if no data/space is currently available. -
readnb(len)
Perform a read operation in a non-blocking fashion. -
writenb(bytes)
Perform a write in a non-blocking fashion.
The following methods are needed for positional read/write:
-
pread(len, offset)
Read up tolenbytes from the stream atoffset. The return value is expected to be aUint8Array. -
pwrite(bytes, offset)
Writebytesto the stream atoffset.bytesis always aUint8Array.
This method is needed if fallocate() is used:
-
allocate(offset, len)
Allocate additional space for the file.
The following methods are optional:
-
advise(offset, len, advice)
Receive advice on how the file will be used.advicecan be 'normal', 'sequential', 'random', 'willNeed', 'dontNeed', and 'noReuse'. -
datasync()
Perform a data sync operation on the file. -
getlock(lock)
Return lock that would conflict with the one given.lockcontains{ type, whence, start, length, pid }. -
setlock(lock, wait)
Create a lock on a particular region of the file.lockcontains{ type, whence, start, length, pid }, whilewaitis the number of nanoseconds to wait until the attempt at locking is abandoned. -
sync()
Perform a sync operation on the file.
When an optional method is undefined, the caller would be informed that the operation succeeded.
All methods except readnb() and writenb() can be async. These two should throw the following
error when no data/space is available.
class WouldBlock extends Error {
errno = 6; // EAGAIN
constructor() {
super(`Would block`);
}
}Write methods can be omitted when the stream is read-only and vice-versa.
-
size:number
The size of the file.