From 64e97f7e8ecb7c524da3d7dcf45965f690f5ffa3 Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Fri, 26 Apr 2019 16:09:27 -0400 Subject: [PATCH 1/2] Improving fs --- as-pect.config.js | 2 +- packages/ash/assembly/__tests__/cat.spec.ts | 42 ++++++ packages/ash/assembly/__tests__/echo.spec.ts | 73 ++++----- packages/ash/assembly/bin/cat.ts | 4 +- .../assembly/__tests__/wasa.include.ts | 6 + .../assembly/__tests__/wasa.spec.ts | 15 +- packages/assemblyscript/assembly/preamble.ts | 3 +- .../assemblyscript/assembly/wasa/mock/fs.ts | 102 ++++++++++--- .../assembly/wasa/mock/index.ts | 131 ++++++++++------ types/assembly/index.d.ts | 2 + types/wasa/index.d.ts | 140 +++++++++++------- 11 files changed, 354 insertions(+), 166 deletions(-) create mode 100644 packages/ash/assembly/__tests__/cat.spec.ts create mode 100644 packages/assemblyscript/assembly/__tests__/wasa.include.ts diff --git a/as-pect.config.js b/as-pect.config.js index 150b126..a283c71 100644 --- a/as-pect.config.js +++ b/as-pect.config.js @@ -8,7 +8,7 @@ module.exports = { /** * A set of globs passed to the glob package that quality files to be added to each test. */ - add: [], + add: ["packages/assemblyscript/assembly/__tests__/wasa.include.ts"], /** * All the compiler flags needed for this test suite. Make sure that a binary file is output. */ diff --git a/packages/ash/assembly/__tests__/cat.spec.ts b/packages/ash/assembly/__tests__/cat.spec.ts new file mode 100644 index 0000000..7d186ba --- /dev/null +++ b/packages/ash/assembly/__tests__/cat.spec.ts @@ -0,0 +1,42 @@ + +import { main as cat } from "../bin/cat"; + +let Hello = "Hello"; +let World = "World"; +let testFile: usize = 0; +type fd = usize; + + +function openStdout(): fd { + return fs.openForRead("/dev/fd/1"); +} + +var stdout: fd; +var stdout2: fd; + +describe("cat", (): void => { + + beforeEach((): void => { + // testFile = fs.openForWrite("/test"); + // fs.writeString(testFile, Hello + " " + World); + // fs.reset(Console.stdout); + // fs.reset(stdout); + // stdout2 = openStdout(); + // fs.erase(stdout); + // CommandLine.reset(); + // CommandLine.push("cat"); + + }) + + it("should print newline by default", (): void => { + // CommandLine.push("/test") + // cat(CommandLine.all()) + // let str = Hello + " " + World + "\n"; + // expect(fs.tell(stdout)).toBe(str.lengthUTF8, "Two extra characters for space and \\n") + // fs.reset(stdout); + // expect(fs.readString(stdout)).toBe(Hello + " " + World + "\n") + // fs.reset(stdout); + // expect(fs.readString(stdout)).toBe(fs.readString(stdout2)); + }) + +}) diff --git a/packages/ash/assembly/__tests__/echo.spec.ts b/packages/ash/assembly/__tests__/echo.spec.ts index b8f7944..39e382c 100644 --- a/packages/ash/assembly/__tests__/echo.spec.ts +++ b/packages/ash/assembly/__tests__/echo.spec.ts @@ -1,55 +1,56 @@ -import { Console, IO, fs, CommandLine } from "../../../assemblyscript/assembly/wasa/mock"; -import { FileDescriptor, File } from "../../../assemblyscript/assembly/wasa/mock/fs"; - -import { main } from "../bin/echo"; +import { main as echo } from "../bin/echo"; let Hello = "Hello"; let World = "World"; +let testFile: usize = 0; -function openFile(path: string): FileDescriptor { - return fs.get(fs.openFile(path)); -} +type fd = usize; -function openStdout(): FileDescriptor { - return openFile("/dev/fd/1"); +function openStdout(): fd { + return fs.openForRead("/dev/fd/1"); } -var stdout: FileDescriptor; -var stdout2: FileDescriptor; +var stdout: fd; +var stdout2: fd; + +describe("cat", (): void => { -describe("echo", (): void => { beforeEach((): void => { - stdout = fs.get(Console.stdout) - stdout.reset() + testFile = fs.openForWrite("/test"); + fs.writeString(testFile, Hello + " " + World); + fs.reset(Console.stdout); + fs.reset(stdout); stdout2 = openStdout(); - stdout.file.erase(); - CommandLine._args = new Array(); - CommandLine.push("echo"); + fs.erase(stdout); + CommandLine.reset(); + CommandLine.push("cat"); }) it("should print newline by default", (): void => { - CommandLine.push(Hello) - CommandLine.push(World) - main(CommandLine.all()) - let str = Hello + " " + World + "\n"; - expect(stdout.offset).toBe(str.lengthUTF8, "Two extra characters for space and \\n") - stdout.reset(); - expect(stdout.readString()).toBe(Hello + " " + World + "\n") - stdout.reset(); - expect(stdout.readString()).toBe(stdout2.readString()); + // CommandLine.push(Hello) + // CommandLine.push(World) + // echo(CommandLine.all()) + // let str = Hello + " " + World + "\n"; + // expect(fs.tell(stdout)).toBe(str.lengthUTF8, "Two extra characters for space and \\n") + // fs.reset(stdout); + // expect(fs.readString(stdout)).toBe(Hello + " " + World + "\n") + // fs.reset(stdout); + // expect(fs.readString(stdout)).toBe(fs.readString(stdout2)); + }) it("should print no newline with -n", () => { - CommandLine.push("-n") - CommandLine.push(Hello) - CommandLine.push(World) - log(CommandLine.all()) - main(CommandLine.all()) - let offset = stdout.offset - let str = Hello + " " + World; - expect(offset).toBe(str.lengthUTF8, "One extra character for space") - stdout.reset() - expect(stdout.readString()).toBe(Hello + " " + World) + // CommandLine.push("-n") + // CommandLine.push(Hello) + // CommandLine.push(World) + // echo(CommandLine.all()) + // let offset = fs.tell(stdout); + // let str = Hello + " " + World; + // expect(fs.tell(stdout)).toBe(str.lengthUTF8, "Two extra characters for space and \\n") + // fs.reset(stdout); + // expect(fs.readString(stdout)).toBe(Hello + " " + World + "\n") + // fs.reset(stdout); + // expect(fs.readString(stdout)).toBe(fs.readString(stdout2)); }) }) diff --git a/packages/ash/assembly/bin/cat.ts b/packages/ash/assembly/bin/cat.ts index 392f7d8..a15ee85 100644 --- a/packages/ash/assembly/bin/cat.ts +++ b/packages/ash/assembly/bin/cat.ts @@ -2,8 +2,8 @@ export function main(args: string[]): void { if (args.length > 1) { - for (let i: usize = 1; i < args.length; i++) { - let fd = fs.open(args[i]); + for (let i: i32 = 1; i < args.length; i++) { + let fd = fs.openForRead(args[i]); Console.log(fs.readString(fd)) } } diff --git a/packages/assemblyscript/assembly/__tests__/wasa.include.ts b/packages/assemblyscript/assembly/__tests__/wasa.include.ts new file mode 100644 index 0000000..90bd4b4 --- /dev/null +++ b/packages/assemblyscript/assembly/__tests__/wasa.include.ts @@ -0,0 +1,6 @@ + +import { Console, fs, Process, CommandLine } from '../wasa/mock/index'; +/** This file is included with tests so that the default globals are set up properly. */ +export { Console, fs, Process, CommandLine } +type fd = usize; + diff --git a/packages/assemblyscript/assembly/__tests__/wasa.spec.ts b/packages/assemblyscript/assembly/__tests__/wasa.spec.ts index d876a62..0569714 100644 --- a/packages/assemblyscript/assembly/__tests__/wasa.spec.ts +++ b/packages/assemblyscript/assembly/__tests__/wasa.spec.ts @@ -1,11 +1,10 @@ -import { Console, IO, fs, StringUtils } from "../wasa/mock"; +import { Console, fs, StringUtils } from "../wasa/mock"; import * as echo from "../bin/echo"; import { JSONDecoder } from "../../node_modules/assemblyscript-json/assembly/decoder"; import { JSONEncoder } from "../../node_modules/assemblyscript-json/assembly/encoder"; import { FileDescriptor } from "../wasa/mock/fs"; let jsonStr = '{"hello":"world"}'; - const STDOUT: string = "/dev/fd/1"; var stdout: FileDescriptor; var encoder: JSONEncoder; @@ -38,23 +37,23 @@ function roundripTest(jsonString: string, expectedString: string = ""): bool { beforeAll( (): void => { encoder = new JSONEncoder(); - std_in = fs.get(Console.stdin); - std_out = fs.get(Console.stdout); - std_err = fs.get(Console.stderr); + std_in = fs.fs.get(Console.stdin); + std_out = fs.fs.get(Console.stdout); + std_err = fs.fs.get(Console.stderr); } ); describe("Console", (): void => { it("should be print hello World", (): void => { Console.log(jsonStr); - let std1 = fs.get(std_out.id); - let std2 = fs.get(std_out.id); + let std1 = fs.fs.get(std_out.id); + let std2 = fs.fs.get(std_out.id); expect(std1).toStrictEqual( std2, "Two non-unique file descriptors points to the same object" ); - stdout = fs.get(fs.openFile("/dev/fd/1")); + stdout = fs.fs.get(fs.openForRead("/dev/fd/1")); expect(stdout.offset).toBe( 0, "A fresh file descriptor has a seek (offset) of 0" diff --git a/packages/assemblyscript/assembly/preamble.ts b/packages/assemblyscript/assembly/preamble.ts index c76ce7c..a1d1913 100644 --- a/packages/assemblyscript/assembly/preamble.ts +++ b/packages/assemblyscript/assembly/preamble.ts @@ -9,10 +9,11 @@ import "allocator/arena"; /** * Always needto export memory */ +// @ts-ignore Can export memory export { memory }; /** * The entry function to start the Instance after it's been initialized. */ -export function main(): void {} +export function main(): void { } diff --git a/packages/assemblyscript/assembly/wasa/mock/fs.ts b/packages/assemblyscript/assembly/wasa/mock/fs.ts index 72c5182..7931eee 100644 --- a/packages/assemblyscript/assembly/wasa/mock/fs.ts +++ b/packages/assemblyscript/assembly/wasa/mock/fs.ts @@ -1,9 +1,12 @@ import { StringUtils } from "."; +import { Wasi } from '../../../../kernel/src/wasi/wasi'; type path = string; type fd = usize; export class FileDescriptor { + stat: Wasi.fdstat; + constructor(public file: File, public id: u32, public offset: u32) { } write(bytes: Array): void { @@ -58,14 +61,33 @@ export class FileDescriptor { * Resets the offset to 0 */ reset(): void { - this.seek(0); + this.seek(0, Wasi.whence.SET); } /** * set seek (offset) */ - seek(offset: usize): void { - this.offset = offset + seek(offset: Wasi.filedelta, whence: Wasi.whence = Wasi.whence.CUR): usize { + let newOffset: usize = 0; + switch (whence) { + case Wasi.whence.CUR: { + newOffset = (this.offset + offset); + break; + } + case Wasi.whence.END: { + newOffset = (this.file.length - Math.abs(offset)); + break; + } + case Wasi.whence.SET: { + newOffset = Math.abs(offset); + break; + } + default: { + Process.exit(1) + } + } + this.offset = newOffset; + return newOffset } get data(): usize { @@ -73,18 +95,42 @@ export class FileDescriptor { } } -export class Stdout extends FileDescriptor { - constructor(file: File) { - super(file, 1, 0); +export class DirectoryDescriptor extends FileDescriptor { + + get directory(): Directory { + return this.file as Directory; + } + + get children(): File[] { + return this.directory.children; + } + + addFile(file: File): void { + this.directory.children.push(file); } } export class File { - private _data: ArrayBuffer; - static DefaultSize: u32 = 1024; constructor(public path: string) { this._data = new ArrayBuffer(File.DefaultSize); } + /** + * + * @param type File Type see Wasi.filetype + * @param path Path + * @param dirfd + */ + static create(type: Wasi.filetype, path: string, dirfd: fd): File { + switch (type) { + case Wasi.filetype.DIRECTORY: { + return new Directory(path) + } + } + return new File(path); + } + private _data: ArrayBuffer; + static DefaultSize: u32 = 1024; + get data(): usize { return this._data.data; } @@ -98,6 +144,12 @@ export class File { erase(): void { this._data = new ArrayBuffer(File.DefaultSize); } + + get length(): usize { + return this._data.byteLength; + } + + stat: Wasi.filestat } class Directory extends File { @@ -111,14 +163,13 @@ export class Filesystem { files: Map = new Map(); paths: Map = new Map(); highestFD: usize = 0; - pwd: fd; + + get cwd(): fd { + return Process.cwd + } static Default(): Filesystem { let fs = new Filesystem(); - fs.pwd = fs.openDirectory("/") - fs.openFile("/dev/fd/0") - fs.openFile("/dev/fd/1") - fs.openFile("/dev/fd/2") return fs; } @@ -130,15 +181,19 @@ export class Filesystem { return this.files.get(fd); } - openFile(path: path): fd { + private open(path: path, type: Wasi.filetype, dirfd: fd): fd { let fd = this.highestFD++; if (!this.paths.has(path)) { - this.paths.set(path, new File(path)); + this.paths.set(path, File.create(type, path, fd)); } this.set(fd, new FileDescriptor(this.paths.get(path), fd, 0)); return fd; } + openFile(dirfd: fd, path: path): fd { + return this.open(path, Wasi.filetype.REGULAR_FILE, dirfd); + } + write(fd: fd, data: Array): void { this.get(fd).write(data); } @@ -154,11 +209,20 @@ export class Filesystem { writeString(fd: fd, data: string): void { this.get(fd).writeString(data); } - close(fd: number): void { + + close(fd: fd): void { this.files.delete(fd); } - openDirectory(path: string): fd { - // this.open() - return 0; + + openDirectory(dirfd: fd, path: string): fd { + return this.open(path, Wasi.filetype.DIRECTORY, dirfd); + } + createDirectory(dirfd: fd, path: string): fd { + return this.openDirectory(dirfd, path); } + + erase(fd: fd): void { + this.get(fd).file.erase() + } + } diff --git a/packages/assemblyscript/assembly/wasa/mock/index.ts b/packages/assemblyscript/assembly/wasa/mock/index.ts index d40c753..c59a426 100644 --- a/packages/assemblyscript/assembly/wasa/mock/index.ts +++ b/packages/assemblyscript/assembly/wasa/mock/index.ts @@ -1,20 +1,22 @@ // The entry file of your WebAssembly module. import { RNG } from "./random"; -import { Filesystem as _fs, FileDescriptor, Stdout } from "./fs"; +import { Filesystem as _fs, FileDescriptor } from './fs'; +import { Wasi } from '../../../../kernel/src/wasi/wasi'; -let fs = _fs.Default(); -export { fs }; -export type Descriptor = usize; +type fd = usize; -export class Filesystem { +// @ts-ignore decorator is valid +@global +export class fs { + static readonly fs: _fs = _fs.Default(); /** * A simplified interface to open a file for read operations * @param path Path * @param dirfd Base directory descriptor (will be automatically set soon) */ - static openForRead(path: string, dirfd: Descriptor = 3): Descriptor { - return fs.openFile(path); + static openForRead(path: string, dirfd: fd = 3): fd { + return this.fs.openFile(dirfd, path); } /** @@ -22,23 +24,28 @@ export class Filesystem { * @param path Path * @param dirfd Base directory descriptor (will be automatically set soon) */ - static openForWrite(path: string, dirfd: Descriptor = 3): Descriptor { - return fs.openFile(path); + static openForWrite(path: string, dirfd: fd = 3): fd { + return this.fs.openFile(dirfd, path); } - static openDirectory(path: string): Descriptor { - return fs.openDirectory(path) + static openDirectory(path: string, dirfd: fd): fd { + return this.fs.openDirectory(dirfd, path) + } + /** + * + * @param path path of new directory + * @param dirfd File fd for + */ + static createDirectory(path: string, dirfd: fd = Process.cwd): fd { + return this.fs.createDirectory(dirfd, path); } -} -export class IO { - data: Uint8Array; /** * Close a file descriptor * @param fd file descriptor */ - static close(fd: Descriptor): void { - fs.close(fd); + static close(fd: fd): void { + this.fs.close(fd); } /** @@ -46,8 +53,8 @@ export class IO { * @param fd file descriptor * @param data data */ - static write(fd: Descriptor, data: Array): void { - fs.write(fd, data); + static write(fd: fd, data: Array): void { + this.fs.write(fd, data); } /** @@ -56,9 +63,9 @@ export class IO { * @param s string * @param newline `true` to add a newline after the string */ - static writeString(fd: Descriptor, s: string, newline: bool = false): void { + static writeString(fd: fd, s: string, newline: bool = false): void { let str = s + (newline ? "\n" : ""); - fs.get(fd).writeString(str); + this.fs.get(fd).writeString(str); } /** @@ -66,7 +73,7 @@ export class IO { * @param fd file descriptor * @param s string */ - static writeStringLn(fd: Descriptor, s: string): void { + static writeStringLn(fd: fd, s: string): void { this.writeString(fd, s, true); } @@ -77,11 +84,11 @@ export class IO { * @param chunk_size chunk size (default: 4096) */ static read( - fd: Descriptor, + fd: fd, data: Array = [], chunk_size: usize = 4096 ): Array | null { - fs.get(fd).read(data); + this.fs.get(fd).read(data); return data; } @@ -92,11 +99,11 @@ export class IO { * @param chunk_size chunk size (default: 4096) */ static readAll( - fd: Descriptor, + fd: fd, data: Array = [], chunk_size: usize = 4096 ): Array | null { - data.buffer_ = changetype(fs.get(fd).data); + data.buffer_ = changetype(this.fs.get(fd).data); return data; } @@ -105,46 +112,73 @@ export class IO { * @param fd file descriptor * @param chunk_size chunk size (default: 4096) */ - static readString(fd: Descriptor, chunk_size: usize = 4096): string { - return fs.get(fd).readString(chunk_size) + static readString(fd: fd, chunk_size: usize = 4096): string { + return this.fs.get(fd).readString(chunk_size) } /** * Reach an UTF8 String from a file descriptor until a new line is reached. */ - static readLine(fd: Descriptor, chunk_size: usize = 4096): string { - return fs.get(fd).readLine(chunk_size) + static readLine(fd: fd, chunk_size: usize = 4096): string { + return this.fs.get(fd).readLine(chunk_size) + } + + static reset(fd: fd): void { + this.seek(fd, 0, Wasi.whence.SET); + } + /** + * + * @param fd File fd + * returns the current offset of the file descriptor + */ + static tell(fd: fd): usize { + return this.fs.get(fd).offset; + } + + /** + * + * @param fd File fd + * @param offset The number of bytes to move + * @param whence The base from which the offset is relative + */ + static seek(fd: fd, offset: Wasi.filedelta, whence: Wasi.whence = Wasi.whence.CUR): usize { + return this.get(fd).seek(offset, whence); } - static reset(fd: Descriptor): void { - fs.get(fd).reset(); + static get(fd: fd): FileDescriptor { + return this.fs.get(fd); } + + static erase(fd: fd): void { + this.fs.erase(fd); + } + } // @ts-ignore: Decorators *are* valid here! @global export class Console { - private static _stdin: Descriptor | null = null; - private static _stdout: Descriptor | null = null; - private static _stderr: Descriptor | null = null; + private static _stdin: fd | null = null; + private static _stdout: fd | null = null; + private static _stderr: fd | null = null; - static get stdin(): Descriptor { + static get stdin(): fd { if (Console._stdin == null) { - Console._stdin = Filesystem.openForRead("/dev/fd/0"); + Console._stdin = fs.openForRead("/dev/fd/0"); } return Console._stdin; } - static get stdout(): Descriptor { + static get stdout(): fd { if (Console._stdout == null) { - Console._stdout = Filesystem.openForWrite("/dev/fd/1"); + Console._stdout = fs.openForWrite("/dev/fd/1"); } return Console._stdout; } - static get stderr(): Descriptor { + static get stderr(): fd { if (Console._stderr == null) { - Console._stderr = Filesystem.openForRead("/dev/fd/2"); + Console._stderr = fs.openForRead("/dev/fd/2"); } return Console._stderr; } @@ -155,14 +189,14 @@ export class Console { * @param newline `false` to avoid inserting a newline after the string */ static write(s: string, newline: bool = true): void { - IO.writeString(this.stdout, s, newline); + fs.writeString(this.stdout, s, newline); } /** * Read an UTF8 string from the console, convert it to a native string */ static readAll(): string | null { - return IO.readString(this.stdin); + return fs.readString(this.stdin); } /** @@ -178,7 +212,7 @@ export class Console { * @param newline `false` to avoid inserting a newline after the string */ static error(s: string, newline: bool = true): void { - IO.writeString(this.stdout, s, newline); + fs.writeString(this.stdout, s, newline); } } @@ -233,8 +267,13 @@ export class Process { * @param status exit code */ static exit(status: u32): void { + if (status != Wasi.ExitSuccess) { + abort("Error "); + } abort(); } + + static cwd: fd; } export class EnvironEntry { @@ -298,6 +337,12 @@ export class CommandLine { get args(): Array { return CommandLine._args; } + /** + * Deletes arguments + */ + static reset(): void { + this._args = new Array(); + } } const newLine: u8 = 10; diff --git a/types/assembly/index.d.ts b/types/assembly/index.d.ts index 1e7d0fb..590e877 100644 --- a/types/assembly/index.d.ts +++ b/types/assembly/index.d.ts @@ -1989,3 +1989,5 @@ declare function start( propertyKey: string, descriptor: TypedPropertyDescriptor ): TypedPropertyDescriptor | void; + +declare function abort(str?: string): void \ No newline at end of file diff --git a/types/wasa/index.d.ts b/types/wasa/index.d.ts index d98eb82..b195512 100644 --- a/types/wasa/index.d.ts +++ b/types/wasa/index.d.ts @@ -25,88 +25,116 @@ declare class Console { * @param newline `false` to avoid inserting a newline after the string */ static error(s: string, newline?: boolean): void; -} -// // declare const Cons: number; -// // declare function Cons1(): void; -// // declare type IO = wasa.IO; -declare function abort(): void; + static stdout: fd; + static stderr: fd; + static stdin: fd; +} declare class CommandLine { static all(): Array static push(s: string): void; + static reset(): void; } -declare class FileDescriptor { - // new(public file: File, public id: u32, public offset: u32); - - write(bytes: Array): void; - - writeString(str: string): void; - - copyByte(ptr: usize): void; - - writeByte(byte: u8): void; - - read(bytes: Array): void; - - readByte(): u8; +declare class Process { + static cwd: fd; + static exit(err: usize): void; +} - pread(bytes: Array): void; - readString(): string; +declare class fs { /** - * Resets the offset to 0 + * A simplified interface to open a file for read operations + * @param path Path + * @param dirfd Base directory descriptor (will be automatically set soon) */ - reset(): void; + static openForRead(path: string, dirfd?: fd): fd; /** - * set seek (offset) + * A simplified interface to open a file for write operations + * @param path Path + * @param dirfd Base directory descriptor (will be automatically set soon) */ - seek(offset: usize): void; + static openForWrite(path: string, dirfd?: fd): fd; - data: usize; -} + static openDirectory(path: string): fd; + /** + * Close a file descriptor + * @param fd file descriptor + */ + static close(fd: fd): void; -declare class File { - static DefaultSize: u32; - data: usize; - grow(): File; -} - - -declare class Directory extends File { - parent: Directory; - children: Array; -} - -declare class Filesystem { - files: Map; - paths: Map; - - static Default(): Filesystem; - - set(fd: fd, FD: FileDescriptor): void; + /** + * Write data to a file descriptor + * @param fd file descriptor + * @param data data + */ + static write(fd: fd, data: Array): void; - get(fd: fd): FileDescriptor; + /** + * Write a string to a file descriptor, after encoding it to UTF8 + * @param fd file descriptor + * @param s string + * @param newline `true` to add a newline after the string + */ + static writeString(fd: fd, s: string, newline?: bool): void; - open(path: path): fd; + /** + * Write a string to a file descriptor, after encoding it to UTF8, with a newline + * @param fd file descriptor + * @param s string + */ + static writeStringLn(fd: fd, s: string): void; - write(fd: fd, data: Array): void; + /** + * Read data from a file descriptor + * @param fd file descriptor + * @param data existing array to push data to + * @param chunk_size chunk size (default: 4096) + */ + static read( + fd: fd, + data?: Array, + chunk_size?: usize + ): Array | null; - read(fd: fd, data: Array): void; + /** + * Read from a file descriptor until the end of the stream + * @param fd file descriptor + * @param data existing array to push data to + * @param chunk_size chunk size (default: 4096) + */ + static readAll( + fd: fd, + data?: Array, + chunk_size?: usize + ): Array | null; - readString(fd: fd, offset?: usize): string; + /** + * Read an UTF8 string from a file descriptor, convert it to a native string + * @param fd file descriptor + * @param chunk_size chunk size (default: 4096) + */ + static readString(fd: fd, chunk_size?: usize): string; - writeString(fd: fd, data: string): void; + /** + * Reach an UTF8 String from a file descriptor until a new line is reached. + */ + static readLine(fd: fd, chunk_size?: usize): string; - close(fd: number): void; + static reset(fd: fd): void; - readLine(fd: number, max?: usize): string; -} + static erase(fd: fd): void; -declare var fs: Filesystem; + /** + * + * @param fd File Descriptor + * Returns the current offset of the file descriptor + */ + static tell(fd: fd): usize; +} \ No newline at end of file From b776fa1bcc1175f2607b02a98047f01790f5b070 Mon Sep 17 00:00:00 2001 From: Willem Wyndham Date: Thu, 2 May 2019 21:59:36 -0400 Subject: [PATCH 2/2] Pass tests again But fail to compile with old interface --- as-pect.config.js | 1 - package-lock.json | 26 +- package.json | 6 +- packages/ash/assembly/__tests__/cat.spec.ts | 65 +- packages/ash/assembly/__tests__/echo.spec.ts | 75 +- packages/ash/assembly/__tests__/mocks.ts | 32 + packages/ash/assembly/bin/cat.ts | 4 +- .../assembly/__tests__/json.spec.ts | 37 + .../assembly/__tests__/wasa.include.ts | 21 +- .../assembly/__tests__/wasa.spec.ts | 55 +- .../assemblyscript/assembly/flag/index.ts | 3 + .../assemblyscript/assembly/wasa/index.ts | 41 +- .../assemblyscript/assembly/wasa/mock/fs.ts | 228 ---- .../assembly/wasa/mock/fs/index.ts | 326 +++++ .../assembly/wasa/mock/index.ts | 149 ++- .../assembly/wasa/mock/process.ts | 32 + .../assemblyscript/assembly/wasi/index.ts | 967 +++++++++++++++ tsconfig.json | 22 +- types/wasa/index.d.ts | 137 ++- types/wasi/index.d.ts | 1077 +++++++++++++++++ 20 files changed, 2819 insertions(+), 485 deletions(-) create mode 100644 packages/ash/assembly/__tests__/mocks.ts create mode 100644 packages/assemblyscript/assembly/__tests__/json.spec.ts create mode 100644 packages/assemblyscript/assembly/flag/index.ts delete mode 100644 packages/assemblyscript/assembly/wasa/mock/fs.ts create mode 100644 packages/assemblyscript/assembly/wasa/mock/fs/index.ts create mode 100644 packages/assemblyscript/assembly/wasa/mock/process.ts create mode 100644 packages/assemblyscript/assembly/wasi/index.ts create mode 100644 types/wasi/index.d.ts diff --git a/as-pect.config.js b/as-pect.config.js index a283c71..032ef3b 100644 --- a/as-pect.config.js +++ b/as-pect.config.js @@ -15,7 +15,6 @@ module.exports = { flags: { "--validate": [], "--debug": [], - "--measure": [], /** This is required. Do not change this. */ "--binaryFile": ["output.wasm"] }, diff --git a/package-lock.json b/package-lock.json index 8343395..9d1b327 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1809,7 +1809,7 @@ "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" }, "as-pect": { - "version": "github:jtenner/as-pect#88b80ab69401113a215af31555279d2b585a9df2", + "version": "github:jtenner/as-pect#5ca03818000a6649dfe8b43fe8c3f3951d9d26fd", "from": "github:jtenner/as-pect", "dev": true, "requires": { @@ -1817,26 +1817,10 @@ "chalk": "^2.4.2", "glob": "^7.1.3", "mathjs": "^5.9.0", - "ts-node": "^6.2.0", + "ts-node": "^8.1.0", "yargs-parser": "^13.0.0" }, "dependencies": { - "ts-node": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-6.2.0.tgz", - "integrity": "sha512-ZNT+OEGfUNVMGkpIaDJJ44Zq3Yr0bkU/ugN1PHbU+/01Z7UV1fsELRiTx1KuQNvQ1A3pGh3y25iYF6jXgxV21A==", - "dev": true, - "requires": { - "arrify": "^1.0.0", - "buffer-from": "^1.1.0", - "diff": "^3.1.0", - "make-error": "^1.1.1", - "minimist": "^1.2.0", - "mkdirp": "^0.5.1", - "source-map-support": "^0.5.6", - "yn": "^2.0.0" - } - }, "yargs-parser": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", @@ -10947,12 +10931,6 @@ "camelcase": "^5.0.0", "decamelize": "^1.2.0" } - }, - "yn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", - "dev": true } } } diff --git a/package.json b/package.json index b539b9b..fcd255f 100644 --- a/package.json +++ b/package.json @@ -32,9 +32,11 @@ }, "homepage": "https://github.com/WebAssemblyOS/wasmos#readme", "devDependencies": { + "@types/assembly": "file:./types", "@types/fs-extra": "^5.0.5", "@types/node": "^11.9.5", "@types/webassembly-js-api": "0.0.2", + "@wasmos/utils": "file:./utils", "as-pect": "github:jtenner/as-pect", "browserfs": "git:github.com/jvilk/browserfs", "dropbox": "~4.0.9", @@ -48,9 +50,7 @@ "typescript": "^3.4.2", "webpack": "^4.29.5", "webpack-cli": "^3.2.3", - "webpack-dev-server": "^3.2.0", - "@wasmos/utils": "file:./utils", - "@types/assembly": "file:./types" + "webpack-dev-server": "^3.2.0" }, "dependencies": { "@types/filesystem": "0.0.28", diff --git a/packages/ash/assembly/__tests__/cat.spec.ts b/packages/ash/assembly/__tests__/cat.spec.ts index 7d186ba..6aafa58 100644 --- a/packages/ash/assembly/__tests__/cat.spec.ts +++ b/packages/ash/assembly/__tests__/cat.spec.ts @@ -1,42 +1,41 @@ - import { main as cat } from "../bin/cat"; -let Hello = "Hello"; -let World = "World"; -let testFile: usize = 0; -type fd = usize; +import { Console, fs, Process, CommandLine } from '../../../assemblyscript/assembly/wasa/mock'; +import { FileDescriptor } from '../../../assemblyscript/assembly/wasa/mock/fs'; +import { openStdout, Hello, World, testFile } from './mocks'; -function openStdout(): fd { - return fs.openForRead("/dev/fd/1"); -} -var stdout: fd; -var stdout2: fd; -describe("cat", (): void => { +// var stdout: fd; - beforeEach((): void => { - // testFile = fs.openForWrite("/test"); - // fs.writeString(testFile, Hello + " " + World); - // fs.reset(Console.stdout); - // fs.reset(stdout); - // stdout2 = openStdout(); - // fs.erase(stdout); - // CommandLine.reset(); - // CommandLine.push("cat"); - - }) - - it("should print newline by default", (): void => { - // CommandLine.push("/test") - // cat(CommandLine.all()) - // let str = Hello + " " + World + "\n"; - // expect(fs.tell(stdout)).toBe(str.lengthUTF8, "Two extra characters for space and \\n") - // fs.reset(stdout); - // expect(fs.readString(stdout)).toBe(Hello + " " + World + "\n") - // fs.reset(stdout); - // expect(fs.readString(stdout)).toBe(fs.readString(stdout2)); - }) +var stdout2: FileDescriptor; + +describe("cat", (): void => { + beforeAll( + (): void => { + stdout2 = openStdout(); + testFile().writeString(Hello + " " + World); + } + ); + + beforeEach((): void => { + Console.stdout.reset() + stdout2.reset() + Console.stdout.erase() + CommandLine.reset(); + CommandLine.push("cat"); + }) + + it("should print newline by default", (): void => { + CommandLine.push("/test") + cat(CommandLine.all()) + let str = Hello + " " + World + "\n"; + expect(Console.stdout.tell()).toBe(str.lengthUTF8, "Two extra characters for space and \\n") + Console.stdout.reset() + expect(Console.stdout.readString()).toBe(Hello + " " + World + "\n") + Console.stdout.reset() + expect(Console.stdout.readString()).toBe(stdout2.readString()); + }) }) diff --git a/packages/ash/assembly/__tests__/echo.spec.ts b/packages/ash/assembly/__tests__/echo.spec.ts index 39e382c..95eab25 100644 --- a/packages/ash/assembly/__tests__/echo.spec.ts +++ b/packages/ash/assembly/__tests__/echo.spec.ts @@ -1,56 +1,55 @@ +import { Console, fs, Process, CommandLine } from '../../../assemblyscript/assembly/wasa/mock'; +import { FileDescriptor } from '../../../assemblyscript/assembly/wasa/mock/fs'; +import { openStdout, Hello, World } from './mocks'; import { main as echo } from "../bin/echo"; -let Hello = "Hello"; -let World = "World"; -let testFile: usize = 0; type fd = usize; -function openStdout(): fd { - return fs.openForRead("/dev/fd/1"); -} -var stdout: fd; -var stdout2: fd; -describe("cat", (): void => { +var stdout2: FileDescriptor; +// let stdout = Console.stdout; + + +describe("echo", (): void => { + beforeAll( + (): void => { + stdout2 = openStdout(); + } + ); beforeEach((): void => { - testFile = fs.openForWrite("/test"); - fs.writeString(testFile, Hello + " " + World); - fs.reset(Console.stdout); - fs.reset(stdout); - stdout2 = openStdout(); - fs.erase(stdout); + Console.stdout.reset(); + stdout2.reset(); + Console.stdout.erase() CommandLine.reset(); - CommandLine.push("cat"); - + CommandLine.push("echo"); }) it("should print newline by default", (): void => { - // CommandLine.push(Hello) - // CommandLine.push(World) - // echo(CommandLine.all()) - // let str = Hello + " " + World + "\n"; - // expect(fs.tell(stdout)).toBe(str.lengthUTF8, "Two extra characters for space and \\n") - // fs.reset(stdout); - // expect(fs.readString(stdout)).toBe(Hello + " " + World + "\n") - // fs.reset(stdout); - // expect(fs.readString(stdout)).toBe(fs.readString(stdout2)); - + CommandLine.push(Hello) + CommandLine.push(World) + echo(CommandLine.all()) + let str = Hello + " " + World + "\n"; + let stdoutStr = stdout2.readString() + expect(Console.stdout.tell()).toBe(str.lengthUTF8, "Two extra characters for space and \\n") + Console.stdout.reset(); + expect(Console.stdout.readString()).toBe(Hello + " " + World + "\n") + Console.stdout.reset(); + expect(Console.stdout.readString()).toBe(stdoutStr); }) it("should print no newline with -n", () => { - // CommandLine.push("-n") - // CommandLine.push(Hello) - // CommandLine.push(World) - // echo(CommandLine.all()) - // let offset = fs.tell(stdout); - // let str = Hello + " " + World; - // expect(fs.tell(stdout)).toBe(str.lengthUTF8, "Two extra characters for space and \\n") - // fs.reset(stdout); - // expect(fs.readString(stdout)).toBe(Hello + " " + World + "\n") - // fs.reset(stdout); - // expect(fs.readString(stdout)).toBe(fs.readString(stdout2)); + CommandLine.push("-n") + CommandLine.push(Hello) + CommandLine.push(World) + echo(CommandLine.all()) + let str = Hello + " " + World; + expect(Console.stdout.tell()).toBe(str.lengthUTF8 + 1, "Two extra characters for space and \\n") + Console.stdout.reset(); + expect(Console.stdout.readString()).toBe(str) + Console.stdout.reset(); + expect(Console.stdout.readString()).toBe(stdout2.readString()); }) }) diff --git a/packages/ash/assembly/__tests__/mocks.ts b/packages/ash/assembly/__tests__/mocks.ts new file mode 100644 index 0000000..d2508b8 --- /dev/null +++ b/packages/ash/assembly/__tests__/mocks.ts @@ -0,0 +1,32 @@ +import { Console, fs, Process, CommandLine } from '../../../assemblyscript/assembly/wasa/mock'; +import { FileDescriptor } from '../../../assemblyscript/assembly/wasa/mock/fs'; + +Console.stdin +Console.stdout +Console.stderr + +export function openStdout(): FileDescriptor { + return open("/dev/fd/1"); +} + +export function open(path: string): FileDescriptor { + let FD = fs.openForRead(path) + if (FD.failed) { + abort(); + } + return FD.result; +} + +export function testFile(): FileDescriptor { + let fd = open("/test"); + fd.writeString(Hello_World); + fd.reset(); + return fd; +} + + +export const Hello = "Hello"; +export const World = "World"; +export const Hello_World = Hello + " " + World; + +// export { _Console as Console, fs, Process, CommandLine, FileDescriptor } \ No newline at end of file diff --git a/packages/ash/assembly/bin/cat.ts b/packages/ash/assembly/bin/cat.ts index a15ee85..4a81bae 100644 --- a/packages/ash/assembly/bin/cat.ts +++ b/packages/ash/assembly/bin/cat.ts @@ -3,8 +3,8 @@ export function main(args: string[]): void { if (args.length > 1) { for (let i: i32 = 1; i < args.length; i++) { - let fd = fs.openForRead(args[i]); - Console.log(fs.readString(fd)) + let fd: FileDescriptor = fs.openForRead(args[i]).result; + Console.log(fd.readString()); } } } diff --git a/packages/assemblyscript/assembly/__tests__/json.spec.ts b/packages/assemblyscript/assembly/__tests__/json.spec.ts new file mode 100644 index 0000000..2409b98 --- /dev/null +++ b/packages/assemblyscript/assembly/__tests__/json.spec.ts @@ -0,0 +1,37 @@ +import { JSONDecoder } from "../../node_modules/assemblyscript-json/assembly/decoder"; +import { JSONEncoder } from "../../node_modules/assemblyscript-json/assembly/encoder"; + +var encoder: JSONEncoder; +const jsonStr = '{"hello":"world"}'; +beforeAll( + (): void => { + encoder = new JSONEncoder(); + }); + + +function roundripTest(jsonString: string, expectedString: string = ""): bool { + log("--------" + jsonString + (expectedString ? " " + expectedString : "")); + expectedString = expectedString || jsonString; + let buffer: Uint8Array = new Uint8Array(jsonString.lengthUTF8); + let utf8ptr = jsonString.toUTF8(); + // TODO: std should expose memcpy? + for (let i = 0; i < buffer.length; i++) { + buffer[i] = load(utf8ptr + i); + } + let decoder: JSONDecoder = new JSONDecoder(encoder); + decoder.deserialize(buffer); + let resultBuffer = encoder.serialize(); + let resultString = String.fromUTF8( + resultBuffer.buffer.data, + resultBuffer.length + ); + expect(resultString).toStrictEqual(expectedString); + expect(encoder.toString()).toStrictEqual(expectedString); + return true; +} + +describe("Json", (): void => { + it("simple hello world", (): void => { + roundripTest(jsonStr, jsonStr); + }); +}); \ No newline at end of file diff --git a/packages/assemblyscript/assembly/__tests__/wasa.include.ts b/packages/assemblyscript/assembly/__tests__/wasa.include.ts index 90bd4b4..0ef684a 100644 --- a/packages/assemblyscript/assembly/__tests__/wasa.include.ts +++ b/packages/assemblyscript/assembly/__tests__/wasa.include.ts @@ -1,6 +1,21 @@ -import { Console, fs, Process, CommandLine } from '../wasa/mock/index'; +// import { Console, fs, Process, CommandLine, fd } from '../wasa/mock/index'; +import { Wasi } from "../wasi"; /** This file is included with tests so that the default globals are set up properly. */ -export { Console, fs, Process, CommandLine } -type fd = usize; +//@ts-ignore +// @global +// const Console = _Console; +// Console.stdin +// Console.stdout +// Console.stderr +// let x: fd = 0; +// //@ts-ignore +// const Process = _Process; +//@ts-ignore +// fs.openDirectory("/", fs.openForRead("/.file")) +// CommandLine.reset() +// //@ts-ignore +// const fd = usize; +// //@ts-ignore +// const CommandLine = _CommandLine; diff --git a/packages/assemblyscript/assembly/__tests__/wasa.spec.ts b/packages/assemblyscript/assembly/__tests__/wasa.spec.ts index 0569714..81d3dde 100644 --- a/packages/assemblyscript/assembly/__tests__/wasa.spec.ts +++ b/packages/assemblyscript/assembly/__tests__/wasa.spec.ts @@ -1,80 +1,49 @@ -import { Console, fs, StringUtils } from "../wasa/mock"; -import * as echo from "../bin/echo"; -import { JSONDecoder } from "../../node_modules/assemblyscript-json/assembly/decoder"; -import { JSONEncoder } from "../../node_modules/assemblyscript-json/assembly/encoder"; -import { FileDescriptor } from "../wasa/mock/fs"; - -let jsonStr = '{"hello":"world"}'; +import { Console, StringUtils, fs } from "../wasa/mock"; +import { FileDescriptor } from '../wasa/mock/fs'; const STDOUT: string = "/dev/fd/1"; var stdout: FileDescriptor; -var encoder: JSONEncoder; - +let jsonStr = '{"hello":"world"}'; var std_out: FileDescriptor; var std_in: FileDescriptor; var std_err: FileDescriptor; -function roundripTest(jsonString: string, expectedString: string = ""): bool { - log("--------" + jsonString + (expectedString ? " " + expectedString : "")); - expectedString = expectedString || jsonString; - let buffer: Uint8Array = new Uint8Array(jsonString.lengthUTF8); - let utf8ptr = jsonString.toUTF8(); - // TODO: std should expose memcpy? - for (let i = 0; i < buffer.length; i++) { - buffer[i] = load(utf8ptr + i); - } - let decoder: JSONDecoder = new JSONDecoder(encoder); - decoder.deserialize(buffer); - let resultBuffer = encoder.serialize(); - let resultString = String.fromUTF8( - resultBuffer.buffer.data, - resultBuffer.length - ); - expect(resultString).toStrictEqual(expectedString); - expect(encoder.toString()).toStrictEqual(expectedString); - return true; -} - beforeAll( (): void => { - encoder = new JSONEncoder(); - std_in = fs.fs.get(Console.stdin); - std_out = fs.fs.get(Console.stdout); - std_err = fs.fs.get(Console.stderr); + std_in = Console.stdin; + std_out = Console.stdout; + std_err = Console.stderr; } ); describe("Console", (): void => { it("should be print hello World", (): void => { Console.log(jsonStr); - let std1 = fs.fs.get(std_out.id); - let std2 = fs.fs.get(std_out.id); + let std1 = fs.get(std_out.fd).result; + let std2 = fs.get(std_out.fd).result; expect(std1).toStrictEqual( std2, "Two non-unique file descriptors points to the same object" ); - stdout = fs.fs.get(fs.openForRead("/dev/fd/1")); + stdout = fs.openForRead("/dev/fd/1").result; expect(stdout.offset).toBe( 0, "A fresh file descriptor has a seek (offset) of 0" ); expect(std_out.offset).toBe( - jsonStr.lengthUTF8 + 1, + jsonStr.lengthUTF8 + 1, //Plus nil "length of string + \\n" ); // expect(stdout.offset).toBe(0); //"new line addded" // let stdoutStr = fs.readString(stdout.id); let newLineStr = jsonStr + "\n"; + stdout.reset() expect(stdout.readString()).toStrictEqual(newLineStr); }); }); -describe("Json", (): void => { - it("simple hello world", (): void => { - roundripTest(jsonStr, jsonStr); - }); -}); + describe("readLine", (): void => { it("should read until newline", (): void => { diff --git a/packages/assemblyscript/assembly/flag/index.ts b/packages/assemblyscript/assembly/flag/index.ts new file mode 100644 index 0000000..2abba8c --- /dev/null +++ b/packages/assemblyscript/assembly/flag/index.ts @@ -0,0 +1,3 @@ +export function hasFlag(val: u32, flag: u32): boolean { + return popcnt(val & flag) > 0; +} \ No newline at end of file diff --git a/packages/assemblyscript/assembly/wasa/index.ts b/packages/assemblyscript/assembly/wasa/index.ts index bd54852..eae02fb 100644 --- a/packages/assemblyscript/assembly/wasa/index.ts +++ b/packages/assemblyscript/assembly/wasa/index.ts @@ -1,3 +1,40 @@ -import * as wasa from "@wasmos/wasa"; + import * as mock from "./mock"; -export { wasa }; +import { Wasi } from '../../../kernel/src/wasi/wasi'; + +class Tuple { + constructor(public first: T1, public second: T2) { } +} + + +export class WasiResult extends Tuple { + constructor(first: T | null, second: Wasi.errno = Wasi.errno.SUCCESS) { + super(first, second); + } + get failed(): boolean { + return this.error != Wasi.errno.SUCCESS; + } + + get error(): Wasi.errno { + return this.second + } + + get result(): T { + return this.first!; + } + + static resolve(result: T): WasiResult { + return new WasiResult(result) + } + + static fail(err: Wasi.errno): WasiResult { + return new WasiResult(null, err); + } + + + static void(res: Wasi.errno): WasiResult { + return this.fail(res); + } +} + +export { mock }; diff --git a/packages/assemblyscript/assembly/wasa/mock/fs.ts b/packages/assemblyscript/assembly/wasa/mock/fs.ts deleted file mode 100644 index 7931eee..0000000 --- a/packages/assemblyscript/assembly/wasa/mock/fs.ts +++ /dev/null @@ -1,228 +0,0 @@ -import { StringUtils } from "."; -import { Wasi } from '../../../../kernel/src/wasi/wasi'; - -type path = string; -type fd = usize; - -export class FileDescriptor { - stat: Wasi.fdstat; - - constructor(public file: File, public id: u32, public offset: u32) { } - - write(bytes: Array): void { - for (let i = 0; i < bytes.length; i++) { - this.writeByte(bytes[i]); - } - } - - writeString(str: string): void { - // TODO: std should expose memcpy? - memory.copy(this.data + this.offset, str.toUTF8(), str.lengthUTF8); - this.offset += str.lengthUTF8; - } - - copyByte(ptr: usize): void { - this.writeByte(load(ptr)); - } - - writeByte(byte: u8): void { - store(this.file.data + this.offset++, byte); - } - - read(bytes: Array): void { - for (let i = 0; i < bytes.length; i++) { - bytes[i] = this.readByte(); - } - } - - readByte(): u8 { - return load(this.data + this.offset++); - } - - pread(bytes: Array): void { - let offset = this.offset; - this.read(bytes); - this.offset = offset; - } - - readString(max: usize = 4096): string { - let str = StringUtils.fromCString(this.data + this.offset, max); - this.offset += str.lengthUTF8 + 1; //For null character - return str; - } - - readLine(max?: usize): string { - let str = StringUtils.fromCStringTilNewLine(this.data + this.offset, max); - this.offset += str.lengthUTF8 + 1; //For null character - return str; - } - - /** - * Resets the offset to 0 - */ - reset(): void { - this.seek(0, Wasi.whence.SET); - } - - /** - * set seek (offset) - */ - seek(offset: Wasi.filedelta, whence: Wasi.whence = Wasi.whence.CUR): usize { - let newOffset: usize = 0; - switch (whence) { - case Wasi.whence.CUR: { - newOffset = (this.offset + offset); - break; - } - case Wasi.whence.END: { - newOffset = (this.file.length - Math.abs(offset)); - break; - } - case Wasi.whence.SET: { - newOffset = Math.abs(offset); - break; - } - default: { - Process.exit(1) - } - } - this.offset = newOffset; - return newOffset - } - - get data(): usize { - return this.file.data; - } -} - -export class DirectoryDescriptor extends FileDescriptor { - - get directory(): Directory { - return this.file as Directory; - } - - get children(): File[] { - return this.directory.children; - } - - addFile(file: File): void { - this.directory.children.push(file); - } -} - -export class File { - constructor(public path: string) { - this._data = new ArrayBuffer(File.DefaultSize); - } - /** - * - * @param type File Type see Wasi.filetype - * @param path Path - * @param dirfd - */ - static create(type: Wasi.filetype, path: string, dirfd: fd): File { - switch (type) { - case Wasi.filetype.DIRECTORY: { - return new Directory(path) - } - } - return new File(path); - } - private _data: ArrayBuffer; - static DefaultSize: u32 = 1024; - - get data(): usize { - return this._data.data; - } - - grow(): File { - let newData = new ArrayBuffer(this._data.byteLength * 2); - memory.copy(newData.data, this.data, this._data.byteLength); - return this; - } - - erase(): void { - this._data = new ArrayBuffer(File.DefaultSize); - } - - get length(): usize { - return this._data.byteLength; - } - - stat: Wasi.filestat -} - -class Directory extends File { - parent: Directory; - children: Array; -} - - - -export class Filesystem { - files: Map = new Map(); - paths: Map = new Map(); - highestFD: usize = 0; - - get cwd(): fd { - return Process.cwd - } - - static Default(): Filesystem { - let fs = new Filesystem(); - return fs; - } - - set(fd: fd, FD: FileDescriptor): void { - this.files.set(fd, FD); - } - - get(fd: fd): FileDescriptor { - return this.files.get(fd); - } - - private open(path: path, type: Wasi.filetype, dirfd: fd): fd { - let fd = this.highestFD++; - if (!this.paths.has(path)) { - this.paths.set(path, File.create(type, path, fd)); - } - this.set(fd, new FileDescriptor(this.paths.get(path), fd, 0)); - return fd; - } - - openFile(dirfd: fd, path: path): fd { - return this.open(path, Wasi.filetype.REGULAR_FILE, dirfd); - } - - write(fd: fd, data: Array): void { - this.get(fd).write(data); - } - - read(fd: fd, data: Array): void { - this.get(fd).read(data); - } - - readString(fd: fd, offset: usize = 0): string { - return this.get(fd).readString(); - } - - writeString(fd: fd, data: string): void { - this.get(fd).writeString(data); - } - - close(fd: fd): void { - this.files.delete(fd); - } - - openDirectory(dirfd: fd, path: string): fd { - return this.open(path, Wasi.filetype.DIRECTORY, dirfd); - } - createDirectory(dirfd: fd, path: string): fd { - return this.openDirectory(dirfd, path); - } - - erase(fd: fd): void { - this.get(fd).file.erase() - } - -} diff --git a/packages/assemblyscript/assembly/wasa/mock/fs/index.ts b/packages/assemblyscript/assembly/wasa/mock/fs/index.ts new file mode 100644 index 0000000..4e35a8d --- /dev/null +++ b/packages/assemblyscript/assembly/wasa/mock/fs/index.ts @@ -0,0 +1,326 @@ +import { WasiResult } from '../..'; +import { Wasi } from '../../../wasi/index'; +import { hasFlag } from '../../../flag'; +import { StringUtils } from '..'; + + + +export type path = string; +export type fd = usize; + +export class Ref{ + constructor(public val: T) { } +} + +//@ts-ignore +@global +export class FileDescriptor { + stat: Wasi.fdstat; + + constructor(public fd: fd, public file: File | null, public offset: usize) { } + + write(bytes: Array): Wasi.errno { + memory.copy(this.data + this.offset, bytes.buffer_.data, bytes.length) + this.offset += bytes.length; + return Wasi.errno.SUCCESS; + } + + writeString(str: string, newline: boolean = false): Wasi.errno { + // TODO: Add error checking + let _str = str + (newline ? "\n" : ""); + memory.copy(this.data + this.offset, _str.toUTF8(), _str.lengthUTF8); + this.offset += str.lengthUTF8 + 1; + return Wasi.errno.SUCCESS; + } + + copyByte(ptr: usize): void { + this.writeByte(load(ptr)); + } + + writeByte(byte: u8): void { + store(this.data + this.offset++, byte); + } + + read(bytes: Array): Wasi.errno { + memory.copy(bytes.buffer_.data, this.data + this.offset, bytes.length); + return Wasi.errno.SUCCESS; + } + + readByte(): u8 { + return load(this.data + this.offset++); + } + + pread(bytes: Array): void { + let offset = this.offset; + this.read(bytes); + this.offset = offset; + } + + readString(max: usize = 4096): string { + let str = StringUtils.fromCString(this.data + this.offset, max); + this.offset += str.lengthUTF8 + 1; //For null character + return str; + } + + readLine(max?: usize): string { + let str = StringUtils.fromCStringTilNewLine(this.data + this.offset, max); + this.offset += str.lengthUTF8 + 1; //For null character + return str; + } + + /** + * Resets the offset to 0 + */ + reset(): void { + this.seek(0, Wasi.whence.SET); + } + + /** + * set seek (offset) + */ + seek(offset: Wasi.filedelta, whence: Wasi.whence = Wasi.whence.CUR): usize { + let newOffset: usize = 0; + switch (whence) { + case Wasi.whence.CUR: { + newOffset = (this.offset + offset); + break; + } + case Wasi.whence.END: { + newOffset = (this.length - Math.abs(offset)); + break; + } + case Wasi.whence.SET: { + newOffset = Math.abs(offset); + break; + } + default: { + Process.exit(1) + } + } + this.offset = newOffset; + return newOffset + } + + get length(): usize { + return (this.file != null) ? this.file.length : 0 + } + + get data(): usize { + return (this.file != null) ? this.file.data : 0; + } + + tell(): u32 { + return this.offset; + } + + get ptr(): usize { + return changetype(this) + offsetof("fd"); + } + + erase(): Wasi.errno { + //TODO: Make return error type + return this.file!.erase() + } +} + +export class DirectoryDescriptor extends FileDescriptor { + + get directory(): Directory { + return this.file as Directory; + } + + get children(): File[] { + return this.directory.children; + } + + addFile(file: File): void { + this.directory.children.push(file); + } +} + +export class File { + constructor(public path: string) { + this._data = new ArrayBuffer(File.DefaultSize); + } + /** + * + * @param type File Type see Wasi.filetype + * @param path Path + * @param dirfd + */ + static create(type: Wasi.filetype, path: string, dirfd: fd, options: Wasi.oflags): File { + switch (type) { + case Wasi.filetype.DIRECTORY: { + return new Directory(path) + } + } + return new File(path); + } + private _data: ArrayBuffer; + static DefaultSize: u32 = 1024; + + get data(): usize { + return this._data.data; + } + + grow(): File { + let newData = new ArrayBuffer(this._data.byteLength * 2); + memory.copy(newData.data, this.data, this._data.byteLength); + return this; + } + + erase(): Wasi.errno { + this._data = new ArrayBuffer(File.DefaultSize); + return Wasi.errno.SUCCESS; + } + + get length(): usize { + return this._data.byteLength; + } + + stat: Wasi.filestat +} + +class Directory extends File { + parent: Directory; + children: Array; +} + + +export class FileSystem { + files: Map = new Map(); + paths: Map = new Map(); + highestFD: usize = 77; + nextFD: FileDescriptor; + private _cwd: fd; + get cwd(): fd { + return this._cwd + } + + set cwd(cwd: fd) { + this._cwd = cwd; + } + + static Default(): FileSystem { + return new FileSystem(); + } + + set(fd: fd, FD: FileDescriptor): void { + this.files.set(fd, FD); + } + + get(fd: fd): WasiResult { + if (!this.files.has(fd) || fd <= Wasi.errno.NOTCAPABLE) return WasiResult.fail(Wasi.errno.BADF); + return WasiResult.resolve(this.files.get(fd)); + } + + private _open(path: path, type: Wasi.filetype, dirfd: fd, options: Wasi.oflags): WasiResult { + let fd = this.highestFD++; + if (!this.paths.has(path)) { + if (hasFlag(options, Wasi.oflags.CREAT)) { + log(options) + this.paths.set(path, File.create(type, path, fd, options)); + } else { + return WasiResult.fail(Wasi.errno.NOENT); + } + } + this.set(fd, new FileDescriptor(fd, this.paths.get(path), 0)); + return this.get(fd); + } + + openAt(path: path, type: Wasi.filetype, dirfd: fd, options: Wasi.oflags): WasiResult { + return this._open(path, type, dirfd, options); + } + + open(path: path, type: Wasi.filetype, options: Wasi.oflags): WasiResult { + return this.openAt(path, type, this.cwd, options) + } + + openFileAt(dirfd: fd, path: path): WasiResult { + return this.openAt(path, Wasi.filetype.REGULAR_FILE, dirfd, Wasi.oflags.CREAT); + } + + openFile(path: path): WasiResult { + return this.openFileAt(this.cwd, path); + } + + write(fd: fd, data: Array): Wasi.errno { + let res = this.get(fd) + if (res.error) { + return res.error; + + } + return res.result.write(data); + + } + + read(fd: fd, data: Array): Wasi.errno { + let res = this.get(fd); + if (res.failed) { + return res.error; + } + return res.result.read(data); + } + + readString(fd: fd, offset: usize = 0): WasiResult { + let res = this.get(fd); + if (res.failed) { + return WasiResult.fail(res.error); + } + return WasiResult.resolve(res.result.readString()); + } + + readline(fd: fd, max?: usize): WasiResult { + let res = this.get(fd); + if (res.failed) { + return WasiResult.fail(res.error); + } + return WasiResult.resolve(res.result.readLine(max)); + } + + writeString(fd: fd, data: string, newline: boolean): Wasi.errno { + let res = this.get(fd); + if (res.failed) { + return res.error; + } + return res.result.writeString(data, newline); + } + + close(fd: fd): void { + this.files.delete(fd); + } + + openDirectoryAt(dirfd: fd, path: string, create: boolean = false): WasiResult { + return this.openAt(path, Wasi.filetype.DIRECTORY, dirfd, Wasi.oflags.DIRECTORY | (create ? Wasi.oflags.CREAT : 0)); + } + + createDirectoryAt(dirfd: fd, path: string): WasiResult { + return this.openDirectoryAt(dirfd, path, true); + } + + openDirectory(path: string, create: boolean = false): WasiResult { + return this.openDirectoryAt(this.cwd, path, create); + } + + createDirectory(path: string): WasiResult { + return this.createDirectoryAt(this.cwd, path); + } + + erase(fd: fd): WasiResult { + let res = this.get(fd); + if (res.failed) { + return WasiResult.fail(res.error); + } + return WasiResult.void(this.get(fd).result.erase()); + } + + seek(fd: fd, offset: Wasi.filedelta, whence: Wasi.whence = Wasi.whence.CUR): WasiResult> { + let res = this.get(fd); + if (res.failed) { + return WasiResult.fail(res.error); + } + return WasiResult.resolve(new Ref(res.result.seek(offset, whence))); + } +} + + diff --git a/packages/assemblyscript/assembly/wasa/mock/index.ts b/packages/assemblyscript/assembly/wasa/mock/index.ts index c59a426..344b53a 100644 --- a/packages/assemblyscript/assembly/wasa/mock/index.ts +++ b/packages/assemblyscript/assembly/wasa/mock/index.ts @@ -1,22 +1,33 @@ // The entry file of your WebAssembly module. import { RNG } from "./random"; -import { Filesystem as _fs, FileDescriptor } from './fs'; -import { Wasi } from '../../../../kernel/src/wasi/wasi'; -type fd = usize; +import { WasiResult } from ".."; +export { WasiResult } +import { FileSystem, FileDescriptor, fd, Ref } from "./fs"; +// export { FileDescriptor } + +let DefaultFS = FileSystem.Default(); // @ts-ignore decorator is valid @global export class fs { - static readonly fs: _fs = _fs.Default(); + private static _fs: FileSystem = DefaultFS; + + static set fs(_fs: FileSystem) { + fs._fs = _fs; + } + + static get fs(): FileSystem { + return fs._fs; + } /** * A simplified interface to open a file for read operations * @param path Path * @param dirfd Base directory descriptor (will be automatically set soon) */ - static openForRead(path: string, dirfd: fd = 3): fd { - return this.fs.openFile(dirfd, path); + static openForRead(path: string, dirfd: fd = 3): WasiResult { + return this.fs.openFileAt(dirfd, path); } /** @@ -24,20 +35,20 @@ export class fs { * @param path Path * @param dirfd Base directory descriptor (will be automatically set soon) */ - static openForWrite(path: string, dirfd: fd = 3): fd { - return this.fs.openFile(dirfd, path); + static openForWrite(path: string, dirfd: fd = 3): WasiResult { + return this.fs.openFileAt(dirfd, path); } - static openDirectory(path: string, dirfd: fd): fd { - return this.fs.openDirectory(dirfd, path) + static openDirectory(path: string, dirfd: fd): WasiResult { + return this.fs.openDirectoryAt(dirfd, path) } /** * * @param path path of new directory * @param dirfd File fd for */ - static createDirectory(path: string, dirfd: fd = Process.cwd): fd { - return this.fs.createDirectory(dirfd, path); + static createDirectory(path: string, dirfd: fd = this.fs.cwd): WasiResult { + return this.fs.createDirectoryAt(dirfd, path); } /** @@ -53,8 +64,8 @@ export class fs { * @param fd file descriptor * @param data data */ - static write(fd: fd, data: Array): void { - this.fs.write(fd, data); + static write(fd: fd, data: Array): Wasi.errno { + return this.fs.write(fd, data); } /** @@ -63,9 +74,8 @@ export class fs { * @param s string * @param newline `true` to add a newline after the string */ - static writeString(fd: fd, s: string, newline: bool = false): void { - let str = s + (newline ? "\n" : ""); - this.fs.get(fd).writeString(str); + static writeString(fd: fd, s: string, newline: boolean = false): Wasi.errno { + return this.fs.writeString(fd, s, newline); } /** @@ -73,8 +83,8 @@ export class fs { * @param fd file descriptor * @param s string */ - static writeStringLn(fd: fd, s: string): void { - this.writeString(fd, s, true); + static writeStringLn(fd: fd, s: string): Wasi.errno { + return this.writeString(fd, s, true); } /** @@ -83,13 +93,8 @@ export class fs { * @param data existing array to push data to * @param chunk_size chunk size (default: 4096) */ - static read( - fd: fd, - data: Array = [], - chunk_size: usize = 4096 - ): Array | null { - this.fs.get(fd).read(data); - return data; + static read(fd: fd, data: Array = [], chunk_size: usize = 4096): Wasi.errno { + return this.fs.read(fd, data); } /** @@ -98,13 +103,12 @@ export class fs { * @param data existing array to push data to * @param chunk_size chunk size (default: 4096) */ - static readAll( - fd: fd, - data: Array = [], - chunk_size: usize = 4096 - ): Array | null { - data.buffer_ = changetype(this.fs.get(fd).data); - return data; + static readAll(fd: fd, data: Array = [], chunk_size: usize = 4096): Wasi.errno { + if (this.fs.get(fd).failed) { + return Wasi.errno.BADF; + } + data.buffer_ = changetype(this.fs.get(fd).result.data); + return Wasi.errno.SUCCESS; } /** @@ -112,15 +116,15 @@ export class fs { * @param fd file descriptor * @param chunk_size chunk size (default: 4096) */ - static readString(fd: fd, chunk_size: usize = 4096): string { - return this.fs.get(fd).readString(chunk_size) + static readString(fd: fd, chunk_size: usize = 4096): WasiResult { + return this.fs.readString(fd, chunk_size) } /** * Reach an UTF8 String from a file descriptor until a new line is reached. */ - static readLine(fd: fd, chunk_size: usize = 4096): string { - return this.fs.get(fd).readLine(chunk_size) + static readLine(fd: fd, chunk_size: usize = 4096): WasiResult { + return this.fs.readline(fd, chunk_size) } static reset(fd: fd): void { @@ -132,7 +136,8 @@ export class fs { * returns the current offset of the file descriptor */ static tell(fd: fd): usize { - return this.fs.get(fd).offset; + // TODO: add error check + return this.fs.get(fd).result.offset; } /** @@ -141,11 +146,11 @@ export class fs { * @param offset The number of bytes to move * @param whence The base from which the offset is relative */ - static seek(fd: fd, offset: Wasi.filedelta, whence: Wasi.whence = Wasi.whence.CUR): usize { - return this.get(fd).seek(offset, whence); + static seek(fd: fd, offset: Wasi.filedelta, whence: Wasi.whence = Wasi.whence.CUR): WasiResult> { + return this.fs.seek(fd, offset, whence); } - static get(fd: fd): FileDescriptor { + static get(fd: fd): WasiResult { return this.fs.get(fd); } @@ -155,32 +160,36 @@ export class fs { } + +export * from "./process"; + // @ts-ignore: Decorators *are* valid here! @global export class Console { - private static _stdin: fd | null = null; - private static _stdout: fd | null = null; - private static _stderr: fd | null = null; + /** TODO: Add error checking */ + private static _stdin: FileDescriptor | null = null; + private static _stdout: FileDescriptor | null = null; + private static _stderr: FileDescriptor | null = null; - static get stdin(): fd { + static get stdin(): FileDescriptor { if (Console._stdin == null) { - Console._stdin = fs.openForRead("/dev/fd/0"); + Console._stdin = fs.openForRead("/dev/fd/0").result; } - return Console._stdin; + return Console._stdin!; } - static get stdout(): fd { + static get stdout(): FileDescriptor { if (Console._stdout == null) { - Console._stdout = fs.openForWrite("/dev/fd/1"); + Console._stdout = fs.openForWrite("/dev/fd/1").result; } - return Console._stdout; + return Console._stdout!; } - static get stderr(): fd { + static get stderr(): FileDescriptor { if (Console._stderr == null) { - Console._stderr = fs.openForRead("/dev/fd/2"); + Console._stderr = fs.openForRead("/dev/fd/2").result; } - return Console._stderr; + return Console._stderr!; } /** @@ -188,22 +197,22 @@ export class Console { * @param s string * @param newline `false` to avoid inserting a newline after the string */ - static write(s: string, newline: bool = true): void { - fs.writeString(this.stdout, s, newline); + static write(s: string, newline: boolean = false): void { + this.stdout.writeString(s, newline); } /** * Read an UTF8 string from the console, convert it to a native string */ static readAll(): string | null { - return fs.readString(this.stdin); + return this.stdin.readString(); } /** * Alias for `Console.write()` */ static log(s: string): void { - this.write(s); + this.write(s, true); } /** @@ -211,8 +220,8 @@ export class Console { * @param s string * @param newline `false` to avoid inserting a newline after the string */ - static error(s: string, newline: bool = true): void { - fs.writeString(this.stdout, s, newline); + static error(s: string, newline: boolean = true): void { + this.stderr.writeString(s, newline); } } @@ -261,20 +270,6 @@ export class Performance { } } -export class Process { - /** - * Cleanly terminate the current process - * @param status exit code - */ - static exit(status: u32): void { - if (status != Wasi.ExitSuccess) { - abort("Error "); - } - abort(); - } - - static cwd: fd; -} export class EnvironEntry { constructor(readonly key: string, readonly value: string) { } @@ -307,7 +302,8 @@ export class Environ { return null; } } - +//@ts-ignore +@global export class CommandLine { static _args: Array = new Array(); @@ -341,7 +337,9 @@ export class CommandLine { * Deletes arguments */ static reset(): void { - this._args = new Array(); + while (this._args.length > 0) { + this._args.pop(); + } } } @@ -371,3 +369,4 @@ export class StringUtils { return String.fromUTF8(cstring, size); } } + diff --git a/packages/assemblyscript/assembly/wasa/mock/process.ts b/packages/assemblyscript/assembly/wasa/mock/process.ts new file mode 100644 index 0000000..fc3382c --- /dev/null +++ b/packages/assemblyscript/assembly/wasa/mock/process.ts @@ -0,0 +1,32 @@ +import { fd } from "./fs"; +import { Wasi } from "../../wasi"; + +//@ts-ignore +@global +export class Process { + static _singleton: Process; + + constructor(cwd: fd) { + this._cwd = cwd; + Process._singleton = this; + } + _cwd: fd; + /** + * Cleanly terminate the current process + * @param status exit code + */ + static exit(status: Wasi.errno): void { + if (status != Wasi.errno.SUCCESS) { + abort("Error "); + } + abort(); + } + + static get cwd(): fd { + return Process._singleton._cwd; + } + + static set cwd(fd: fd) { + Process._singleton._cwd = fd; + } +} \ No newline at end of file diff --git a/packages/assemblyscript/assembly/wasi/index.ts b/packages/assemblyscript/assembly/wasi/index.ts new file mode 100644 index 0000000..d4a5eef --- /dev/null +++ b/packages/assemblyscript/assembly/wasi/index.ts @@ -0,0 +1,967 @@ + +export namespace Wasi { + + // === Types ====================================================================================== + + /** File or memory access pattern advisory information. */ + export namespace advice { + /** The application has no advice to give on its behavior with respect to the specified data. */ + // @ts-ignore: decorator + @inline + export const NORMAL: advice = 0; + /** The application expects to access the specified data sequentially from lower offsets to higher offsets. */ + // @ts-ignore: decorator + @inline + export const SEQUENTIAL: advice = 1; + /** The application expects to access the specified data in a random order. */ + // @ts-ignore: decorator + @inline + export const RANDOM: advice = 2; + /** The application expects to access the specified data in the near future. */ + // @ts-ignore: decorator + @inline + export const WILLNEED: advice = 3; + /** The application expects that it will not access the specified data in the near future. */ + // @ts-ignore: decorator + @inline + export const DONTNEED: advice = 4; + /** The application expects to access the specified data once and then not reuse it thereafter. */ + // @ts-ignore: decorator + @inline + export const NOREUSE: advice = 5; + } + export type advice = u8; + + /** Identifiers for clocks. */ + export namespace clockid { + /** The clock measuring real time. Time value zero corresponds with 1970-01-01T00:00:00Z. */ + // @ts-ignore: decorator + @inline + export const REALTIME: clockid = 0; + /** The store-wide monotonic clock. Absolute value has no meaning. */ + // @ts-ignore: decorator + @inline + export const MONOTONIC: clockid = 1; + /** The CPU-time clock associated with the current process. */ + // @ts-ignore: decorator + @inline + export const PROCESS_CPUTIME_ID: clockid = 2; + /** The CPU-time clock associated with the current thread. */ + // @ts-ignore: decorator + @inline + export const THREAD_CPUTIME_ID: clockid = 3; + } + export type clockid = u32; + + /** Identifier for a device containing a file system. Can be used in combination with `inode` to uniquely identify a file or directory in the filesystem. */ + export type device = u64; + + /** A reference to the offset of a directory entry. */ + export type dircookie = u64; + + /** A directory entry. */ + @unmanaged export class dirent { + /** The offset of the next directory entry stored in this directory. */ + next: dircookie; + /** The serial number of the file referred to by this directory entry. */ + ino: inode; + /** The length of the name of the directory entry. */ + namlen: u32; + /** The type of the file referred to by this directory entry. */ + type: filetype; + private __padding0: u16; + } + + /** Error codes returned by functions. */ + export namespace errno { + /** No error occurred. System call completed successfully. */ + // @ts-ignore: decorator + @inline + export const SUCCESS: errno = 0; + /** Argument list too long. */ + // @ts-ignore: decorator + @inline + export const TOOBIG: errno = 1; + /** Permission denied. */ + // @ts-ignore: decorator + @inline + export const ACCES: errno = 2; + /** Address in use. */ + // @ts-ignore: decorator + @inline + export const ADDRINUSE: errno = 3; + /** Address not available. */ + // @ts-ignore: decorator + @inline + export const ADDRNOTAVAIL: errno = 4; + /** Address family not supported. */ + // @ts-ignore: decorator + @inline + export const AFNOSUPPORT: errno = 5; + /** Resource unavailable, or operation would block. */ + // @ts-ignore: decorator + @inline + export const AGAIN: errno = 6; + /** Connection already in progress. */ + // @ts-ignore: decorator + @inline + export const ALREADY: errno = 7; + /** Bad file descriptor. */ + // @ts-ignore: decorator + @inline + export const BADF: errno = 8; + /** Bad message. */ + // @ts-ignore: decorator + @inline + export const BADMSG: errno = 9; + /** Device or resource busy. */ + // @ts-ignore: decorator + @inline + export const BUSY: errno = 10; + /** Operation canceled. */ + // @ts-ignore: decorator + @inline + export const CANCELED: errno = 11; + /** No child processes. */ + // @ts-ignore: decorator + @inline + export const CHILD: errno = 12; + /** Connection aborted. */ + // @ts-ignore: decorator + @inline + export const CONNABORTED: errno = 13; + /** Connection refused. */ + // @ts-ignore: decorator + @inline + export const CONNREFUSED: errno = 14; + /** Connection reset. */ + // @ts-ignore: decorator + @inline + export const CONNRESET: errno = 15; + /** Resource deadlock would occur. */ + // @ts-ignore: decorator + @inline + export const DEADLK: errno = 16; + /** Destination address required. */ + // @ts-ignore: decorator + @inline + export const DESTADDRREQ: errno = 17; + /** Mathematics argument out of domain of function. */ + // @ts-ignore: decorator + @inline + export const DOM: errno = 18; + /** Reserved. */ + // @ts-ignore: decorator + @inline + export const DQUOT: errno = 19; + /** File exists. */ + // @ts-ignore: decorator + @inline + export const EXIST: errno = 20; + /** Bad address. */ + // @ts-ignore: decorator + @inline + export const FAULT: errno = 21; + /** File too large. */ + // @ts-ignore: decorator + @inline + export const FBIG: errno = 22; + /** Host is unreachable. */ + // @ts-ignore: decorator + @inline + export const HOSTUNREACH: errno = 23; + /** Identifier removed. */ + // @ts-ignore: decorator + @inline + export const IDRM: errno = 24; + /** Illegal byte sequence. */ + // @ts-ignore: decorator + @inline + export const ILSEQ: errno = 25; + /** Operation in progress. */ + // @ts-ignore: decorator + @inline + export const INPROGRESS: errno = 26; + /** Interrupted function. */ + // @ts-ignore: decorator + @inline + export const INTR: errno = 27; + /** Invalid argument. */ + // @ts-ignore: decorator + @inline + export const INVAL: errno = 28; + /** I/O error. */ + // @ts-ignore: decorator + @inline + export const IO: errno = 29; + /** Socket is connected. */ + // @ts-ignore: decorator + @inline + export const ISCONN: errno = 30; + /** Is a directory. */ + // @ts-ignore: decorator + @inline + export const ISDIR: errno = 31; + /** Too many levels of symbolic links. */ + // @ts-ignore: decorator + @inline + export const LOOP: errno = 32; + /** File descriptor value too large. */ + // @ts-ignore: decorator + @inline + export const MFILE: errno = 33; + /** Too many links. */ + // @ts-ignore: decorator + @inline + export const MLINK: errno = 34; + /** Message too large. */ + // @ts-ignore: decorator + @inline + export const MSGSIZE: errno = 35; + /** Reserved. */ + // @ts-ignore: decorator + @inline + export const MULTIHOP: errno = 36; + /** Filename too long. */ + // @ts-ignore: decorator + @inline + export const NAMETOOLONG: errno = 37; + /** Network is down. */ + // @ts-ignore: decorator + @inline + export const NETDOWN: errno = 38; + /** Connection aborted by network. */ + // @ts-ignore: decorator + @inline + export const NETRESET: errno = 39; + /** Network unreachable. */ + // @ts-ignore: decorator + @inline + export const NETUNREACH: errno = 40; + /** Too many files open in system. */ + // @ts-ignore: decorator + @inline + export const NFILE: errno = 41; + /** No buffer space available. */ + // @ts-ignore: decorator + @inline + export const NOBUFS: errno = 42; + /** No such device. */ + // @ts-ignore: decorator + @inline + export const NODEV: errno = 43; + /** No such file or directory. */ + // @ts-ignore: decorator + @inline + export const NOENT: errno = 44; + /** Executable file format error. */ + // @ts-ignore: decorator + @inline + export const NOEXEC: errno = 45; + /** No locks available. */ + // @ts-ignore: decorator + @inline + export const NOLCK: errno = 46; + /** Reserved. */ + // @ts-ignore: decorator + @inline + export const NOLINK: errno = 47; + /** Not enough space. */ + // @ts-ignore: decorator + @inline + export const NOMEM: errno = 48; + /** No message of the desired type. */ + // @ts-ignore: decorator + @inline + export const NOMSG: errno = 49; + /** Protocol not available. */ + // @ts-ignore: decorator + @inline + export const NOPROTOOPT: errno = 50; + /** No space left on device. */ + // @ts-ignore: decorator + @inline + export const NOSPC: errno = 51; + /** Function not supported. */ + // @ts-ignore: decorator + @inline + export const NOSYS: errno = 52; + /** The socket is not connected. */ + // @ts-ignore: decorator + @inline + export const NOTCONN: errno = 53; + /** Not a directory or a symbolic link to a directory. */ + // @ts-ignore: decorator + @inline + export const NOTDIR: errno = 54; + /** Directory not empty. */ + // @ts-ignore: decorator + @inline + export const NOTEMPTY: errno = 55; + /** State not recoverable. */ + // @ts-ignore: decorator + @inline + export const NOTRECOVERABLE: errno = 56; + /** Not a socket. */ + // @ts-ignore: decorator + @inline + export const NOTSOCK: errno = 57; + /** Not supported, or operation not supported on socket. */ + // @ts-ignore: decorator + @inline + export const NOTSUP: errno = 58; + /** Inappropriate I/O control operation. */ + // @ts-ignore: decorator + @inline + export const NOTTY: errno = 59; + /** No such device or address. */ + // @ts-ignore: decorator + @inline + export const NXIO: errno = 60; + /** Value too large to be stored in data type. */ + // @ts-ignore: decorator + @inline + export const OVERFLOW: errno = 61; + /** Previous owner died. */ + // @ts-ignore: decorator + @inline + export const OWNERDEAD: errno = 62; + /** Operation not permitted. */ + // @ts-ignore: decorator + @inline + export const PERM: errno = 63; + /** Broken pipe. */ + // @ts-ignore: decorator + @inline + export const PIPE: errno = 64; + /** Protocol error. */ + // @ts-ignore: decorator + @inline + export const PROTO: errno = 65; + /** Protocol not supported. */ + // @ts-ignore: decorator + @inline + export const PROTONOSUPPORT: errno = 66; + /** Protocol wrong type for socket. */ + // @ts-ignore: decorator + @inline + export const PROTOTYPE: errno = 67; + /** Result too large. */ + // @ts-ignore: decorator + @inline + export const RANGE: errno = 68; + /** Read-only file system. */ + // @ts-ignore: decorator + @inline + export const ROFS: errno = 69; + /** Invalid seek. */ + // @ts-ignore: decorator + @inline + export const SPIPE: errno = 70; + /** No such process. */ + // @ts-ignore: decorator + @inline + export const SRCH: errno = 71; + /** Reserved. */ + // @ts-ignore: decorator + @inline + export const STALE: errno = 72; + /** Connection timed out. */ + // @ts-ignore: decorator + @inline + export const TIMEDOUT: errno = 73; + /** Text file busy. */ + // @ts-ignore: decorator + @inline + export const TXTBSY: errno = 74; + /** Cross-device link. */ + // @ts-ignore: decorator + @inline + export const XDEV: errno = 75; + /** Extension: Capabilities insufficient. */ + // @ts-ignore: decorator + @inline + export const NOTCAPABLE: errno = 76; + } + export type errno = u16; + + /** An event that occurred. */ + @unmanaged export abstract class event { + /** User-provided value that got attached to `subscription#userdata`. */ + userdata: userdata; + /** If non-zero, an error that occurred while processing the subscription request. */ + error: errno; + /* The type of the event that occurred. */ + type: eventtype; + private __padding0: u16; + } + + /** An event that occurred when type is `eventtype.FD_READ` or `eventtype.FD_WRITE`. */ + @unmanaged export class rwevent extends event { + /* The number of bytes available for reading or writing. */ + nbytes: filesize; + /* The state of the file descriptor. */ + flags: eventrwflags; + private __padding1: u32; + } + + /** The state of the file descriptor subscribed to with `eventtype.FD_READ` or `eventtype.FD_WRITE`. */ + export namespace eventrwflags { + /** The peer of this socket has closed or disconnected. */ + // @ts-ignore: decorator + @inline + export const HANGUP: eventrwflags = 1; + } + export type eventrwflags = u16; + + /** Type of a subscription to an event or its occurrence. */ + export namespace eventtype { + /** The time value of clock has reached the timestamp. */ + // @ts-ignore: decorator + @inline + export const CLOCK: eventtype = 0; + /** File descriptor has data available for reading. */ + // @ts-ignore: decorator + @inline + export const FD_READ: eventtype = 1; + /** File descriptor has capacity available for writing */ + // @ts-ignore: decorator + @inline + export const FD_WRITE: eventtype = 2; + } + export type eventtype = u8; + + /** Exit code generated by a process when exiting. */ + export type exitcode = u32; + + /** A file descriptor number. */ + export type fd = u32; + + /** File descriptor flags. */ + export namespace fdflags { + /** Append mode: Data written to the file is always appended to the file's end. */ + // @ts-ignore: decorator + @inline + export const APPEND: fdflags = 1; + /** Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized. */ + // @ts-ignore: decorator + @inline + export const DSYNC: fdflags = 2; + /** Non-blocking mode. */ + // @ts-ignore: decorator + @inline + export const NONBLOCK: fdflags = 4; + /** Synchronized read I/O operations. */ + // @ts-ignore: decorator + @inline + export const RSYNC: fdflags = 8; + /** Write according to synchronized I/O file integrity completion. */ + // @ts-ignore: decorator + @inline + export const SYNC: fdflags = 16; + } + export type fdflags = u16; + + /** File descriptor attributes. */ + @unmanaged export class fdstat { + /** File type. */ + filetype: filetype; + /** File descriptor flags. */ + flags: fdflags; + /** Rights that apply to this file descriptor. */ + rights_base: rights; + /** Maximum set of rights that may be installed on new file descriptors that are created through this file descriptor, e.g., through `path_open`. */ + rights_inheriting: rights; + } + + /** Relative offset within a file. */ + export type filedelta = i64; + + /** Non-negative file size or length of a region within a file. */ + export type filesize = u64; + + /** File attributes. */ + @unmanaged export class filestat { + /** Device ID of device containing the file. */ + dev: device; + /** File serial number. */ + ino: inode; + /** File type. */ + filetype: filetype; + /** Number of hard links to the file. */ + nlink: linkcount; + /** For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. */ + size: filesize; + /** Last data access timestamp. */ + atim: timestamp; + /** Last data modification timestamp. */ + mtim: timestamp; + /** Last file status change timestamp. */ + ctim: timestamp; + } + + /** The type of a file descriptor or file. */ + export namespace filetype { + /** The type of the file descriptor or file is unknown or is different from any of the other types specified. */ + // @ts-ignore: decorator + @inline + export const UNKNOWN: filetype = 0; + /** The file descriptor or file refers to a block device inode. */ + // @ts-ignore: decorator + @inline + export const BLOCK_DEVICE: filetype = 1; + /** The file descriptor or file refers to a character device inode. */ + // @ts-ignore: decorator + @inline + export const CHARACTER_DEVICE: filetype = 2; + /** The file descriptor or file refers to a directory inode. */ + // @ts-ignore: decorator + @inline + export const DIRECTORY: filetype = 3; + /** The file descriptor or file refers to a regular file inode. */ + // @ts-ignore: decorator + @inline + export const REGULAR_FILE: filetype = 4; + /** The file descriptor or file refers to a datagram socket. */ + // @ts-ignore: decorator + @inline + export const SOCKET_DGRAM: filetype = 5; + /** The file descriptor or file refers to a byte-stream socket. */ + // @ts-ignore: decorator + @inline + export const SOCKET_STREAM: filetype = 6; + /** The file refers to a symbolic link inode. */ + // @ts-ignore: decorator + @inline + export const SYMBOLIC_LINK: filetype = 7; + } + export type filetype = u8; + + /** Which file time attributes to adjust. */ + export namespace fstflags { + /** Adjust the last data access timestamp to the value stored in `filestat#st_atim`. */ + // @ts-ignore: decorator + @inline + export const SET_ATIM: fstflags = 1; + /** Adjust the last data access timestamp to the time of clock `clockid.REALTIME`. */ + // @ts-ignore: decorator + @inline + export const SET_ATIM_NOW: fstflags = 2; + /** Adjust the last data modification timestamp to the value stored in `filestat#st_mtim`. */ + // @ts-ignore: decorator + @inline + export const SET_MTIM: fstflags = 4; + /** Adjust the last data modification timestamp to the time of clock `clockid.REALTIME`. */ + // @ts-ignore: decorator + @inline + export const SET_MTIM_NOW: fstflags = 8; + } + export type fstflags = u16; + + /** File serial number that is unique within its file system. */ + export type inode = u64; + + /** A region of memory for scatter/gather reads. */ + @unmanaged export class iovec { + /** The address of the buffer to be filled. */ + buf: usize; + /** The length of the buffer to be filled. */ + buf_len: usize; + } + + /** Number of hard links to an inode. */ + export type linkcount = u32; + + /** Flags determining the method of how paths are resolved. */ + export namespace lookupflags { + /** As long as the resolved path corresponds to a symbolic link, it is expanded. */ + // @ts-ignore: decorator + @inline + export const SYMLINK_FOLLOW: lookupflags = 1; + } + export type lookupflags = u32; + + /** Open flags. */ + export namespace oflags { + /** Create file if it does not exist. */ + // @ts-ignore: decorator + @inline + export const CREAT: oflags = 1; + /** Fail if not a directory. */ + // @ts-ignore: decorator + @inline + export const DIRECTORY: oflags = 2; + /** Fail if file already exists. */ + // @ts-ignore: decorator + @inline + export const EXCL: oflags = 4; + /** Truncate file to size 0. */ + // @ts-ignore: decorator + @inline + export const TRUNC: oflags = 8; + } + export type oflags = u16; + + // TODO: undocumented + export namespace preopentype { + // @ts-ignore: decorator + @inline + export const DIR: preopentype = 0; + } + export type preopentype = u8; + + // TODO: undocumented + export abstract class prestat { + type: preopentype; + } + + // TODO: undocumented + export class dirprestat extends prestat { + name_len: usize; + } + + /** Flags provided to `sock_recv`. */ + export namespace riflags { + /** Returns the message without removing it from the socket's receive queue. */ + // @ts-ignore: decorator + @inline + export const PEEK: riflags = 1; + /** On byte-stream sockets, block until the full amount of data can be returned. */ + // @ts-ignore: decorator + @inline + export const WAITALL: riflags = 2; + } + export type riflags = u16; + + /** File descriptor rights, determining which actions may be performed. */ + export namespace rights { + /** The right to invoke `fd_datasync`. */ + // @ts-ignore: decorator + @inline + export const FD_DATASYNC: rights = 1; + /** The right to invoke `fd_read` and `sock_recv`. */ + // @ts-ignore: decorator + @inline + export const FD_READ: rights = 2; + /** The right to invoke `fd_seek`. This flag implies `rights.FD_TELL`. */ + // @ts-ignore: decorator + @inline + export const FD_SEEK: rights = 4; + /** The right to invoke `fd_fdstat_set_flags`. */ + // @ts-ignore: decorator + @inline + export const FD_FDSTAT_SET_FLAGS: rights = 8; + /** The right to invoke `fd_sync`. */ + // @ts-ignore: decorator + @inline + export const FD_SYNC: rights = 16; + /** The right to invoke `fd_seek` in such a way that the file offset remains unaltered (i.e., `whence.CUR` with offset zero), or to invoke `fd_tell`). */ + // @ts-ignore: decorator + @inline + export const FD_TELL: rights = 32; + /** The right to invoke `fd_write` and `sock_send`. If `rights.FD_SEEK` is set, includes the right to invoke `fd_pwrite`. */ + // @ts-ignore: decorator + @inline + export const FD_WRITE: rights = 64; + /** The right to invoke `fd_advise`. */ + // @ts-ignore: decorator + @inline + export const FD_ADVISE: rights = 128; + /** The right to invoke `fd_allocate`. */ + // @ts-ignore: decorator + @inline + export const FD_ALLOCATE: rights = 256; + /** The right to invoke `path_create_directory`. */ + // @ts-ignore: decorator + @inline + export const PATH_CREATE_DIRECTORY: rights = 512; + /** If `rights.PATH_OPEN` is set, the right to invoke `path_open` with `oflags.CREAT`. */ + // @ts-ignore: decorator + @inline + export const PATH_CREATE_FILE: rights = 1024; + /** The right to invoke `path_link` with the file descriptor as the source directory. */ + // @ts-ignore: decorator + @inline + export const PATH_LINK_SOURCE: rights = 2048; + /** The right to invoke `path_link` with the file descriptor as the target directory. */ + // @ts-ignore: decorator + @inline + export const PATH_LINK_TARGET: rights = 4096; + /** The right to invoke `path_open`. */ + // @ts-ignore: decorator + @inline + export const PATH_OPEN: rights = 8192; + /** The right to invoke `fd_readdir`. */ + // @ts-ignore: decorator + @inline + export const FD_READDIR: rights = 16384; + /** The right to invoke `path_readlink`. */ + // @ts-ignore: decorator + @inline + export const PATH_READLINK: rights = 32768; + /** The right to invoke `path_rename` with the file descriptor as the source directory. */ + // @ts-ignore: decorator + @inline + export const PATH_RENAME_SOURCE: rights = 65536; + /** The right to invoke `path_rename` with the file descriptor as the target directory. */ + // @ts-ignore: decorator + @inline + export const PATH_RENAME_TARGET: rights = 131072; + /** The right to invoke `path_filestat_get`. */ + // @ts-ignore: decorator + @inline + export const PATH_FILESTAT_GET: rights = 262144; + /** The right to change a file's size (there is no `path_filestat_set_size`). If `rights.PATH_OPEN` is set, includes the right to invoke `path_open` with `oflags.TRUNC`. */ + // @ts-ignore: decorator + @inline + export const PATH_FILESTAT_SET_SIZE: rights = 524288; + /** The right to invoke `path_filestat_set_times`. */ + // @ts-ignore: decorator + @inline + export const PATH_FILESTAT_SET_TIMES: rights = 1048576; + /** The right to invoke `fd_filestat_get`. */ + // @ts-ignore: decorator + @inline + export const FD_FILESTAT_GET: rights = 2097152; + /** The right to invoke `fd_filestat_set_size`. */ + // @ts-ignore: decorator + @inline + export const FD_FILESTAT_SET_SIZE: rights = 4194304; + /** The right to invoke `fd_filestat_set_times`. */ + // @ts-ignore: decorator + @inline + export const FD_FILESTAT_SET_TIMES: rights = 8388608; + /** The right to invoke `path_symlink`. */ + // @ts-ignore: decorator + @inline + export const RIGHT_PATH_SYMLINK: rights = 16777216; + /** The right to invoke `path_remove_directory`. */ + // @ts-ignore: decorator + @inline + export const PATH_REMOVE_DIRECTORY: rights = 33554432; + /** The right to invoke `path_unlink_file`. */ + // @ts-ignore: decorator + @inline + export const PATH_UNLINK_FILE: rights = 67108864; + /** If `rights.FD_READ` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype.FD_READ`. If `rights.FD_WRITE` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype.FD_WRITE`. */ + // @ts-ignore: decorator + @inline + export const POLL_FD_READWRITE: rights = 134217728; + /** The right to invoke `sock_shutdown`. */ + // @ts-ignore: decorator + @inline + export const SOCK_SHUTDOWN: rights = 268435456; + } + export type rights = u64; + + /** Flags returned by `sock_recv`. */ + export namespace roflags { + /** Message data has been truncated. */ + // @ts-ignore: decorator + @inline + export const DATA_TRUNCATED: roflags = 1; + } + export type roflags = u16; + + /** Which channels on a socket to shut down. */ + export namespace sdflags { + /** Disables further receive operations. */ + // @ts-ignore: decorator + @inline + export const RD: sdflags = 1; + /** Disables further send operations. */ + // @ts-ignore: decorator + @inline + export const WR: sdflags = 2; + } + export type sdflags = u8; + + /** Flags provided to `sock_send`. */ + export namespace siflags { + // As there are currently no flags defined, it must be set to zero. + } + export type siflags = u16; + + /** Signal condition. */ + export namespace signal { + /** Hangup. */ + // @ts-ignore: decorator + @inline + export const HUP: signal = 1; + /** Terminate interrupt signal. */ + // @ts-ignore: decorator + @inline + export const INT: signal = 2; + /** Terminal quit signal. */ + // @ts-ignore: decorator + @inline + export const QUIT: signal = 3; + /** Illegal instruction. */ + // @ts-ignore: decorator + @inline + export const ILL: signal = 4; + /** Trace/breakpoint trap. */ + // @ts-ignore: decorator + @inline + export const TRAP: signal = 5; + /** Process abort signal. */ + // @ts-ignore: decorator + @inline + export const ABRT: signal = 6; + /** Access to an undefined portion of a memory object. */ + // @ts-ignore: decorator + @inline + export const BUS: signal = 7; + /** Erroneous arithmetic operation. */ + // @ts-ignore: decorator + @inline + export const FPE: signal = 8; + /** Kill. */ + // @ts-ignore: decorator + @inline + export const KILL: signal = 9; + /** User-defined signal 1. */ + // @ts-ignore: decorator + @inline + export const USR1: signal = 10; + /** Invalid memory reference. */ + // @ts-ignore: decorator + @inline + export const SEGV: signal = 11; + /** User-defined signal 2. */ + // @ts-ignore: decorator + @inline + export const USR2: signal = 12; + /** Write on a pipe with no one to read it. */ + // @ts-ignore: decorator + @inline + export const PIPE: signal = 13; + /** Alarm clock. */ + // @ts-ignore: decorator + @inline + export const ALRM: signal = 14; + /** Termination signal. */ + // @ts-ignore: decorator + @inline + export const TERM: signal = 15; + /** Child process terminated, stopped, or continued. */ + // @ts-ignore: decorator + @inline + export const CHLD: signal = 16; + /** Continue executing, if stopped. */ + // @ts-ignore: decorator + @inline + export const CONT: signal = 17; + /** Stop executing. */ + // @ts-ignore: decorator + @inline + export const STOP: signal = 18; + /** Terminal stop signal. */ + // @ts-ignore: decorator + @inline + export const TSTP: signal = 19; + /** Background process attempting read. */ + // @ts-ignore: decorator + @inline + export const TTIN: signal = 20; + /** Background process attempting write. */ + // @ts-ignore: decorator + @inline + export const TTOU: signal = 21; + /** High bandwidth data is available at a socket. */ + // @ts-ignore: decorator + @inline + export const URG: signal = 22; + /** CPU time limit exceeded. */ + // @ts-ignore: decorator + @inline + export const XCPU: signal = 23; + /** File size limit exceeded. */ + // @ts-ignore: decorator + @inline + export const XFSZ: signal = 24; + /** Virtual timer expired. */ + // @ts-ignore: decorator + @inline + export const VTALRM: signal = 25; + // @ts-ignore: decorator + @inline + export const PROF: signal = 26; + // @ts-ignore: decorator + @inline + export const WINCH: signal = 27; + // @ts-ignore: decorator + @inline + export const POLL: signal = 28; + // @ts-ignore: decorator + @inline + export const PWR: signal = 29; + /** Bad system call. */ + // @ts-ignore: decorator + @inline + export const SYS: signal = 30; + } + export type signal = u8; + + /** Flags determining how to interpret the timestamp provided in `subscription_t::u.clock.timeout. */ + export namespace subclockflags { + /** If set, treat the timestamp provided in `clocksubscription` as an absolute timestamp. */ + // @ts-ignore: decorator + @inline + export const ABSTIME: subclockflags = 1; + } + export type subclockflags = u16; + + /** Subscription to an event. */ + @unmanaged export abstract class subscription { + /** User-provided value that is attached to the subscription. */ + userdata: userdata; + /** The type of the event to which to subscribe. */ + type: eventtype; + private __padding0: u32; + } + + /* Subscription to an event of type `eventtype.CLOCK`.**/ + @unmanaged export class clocksubscription extends subscription { + /** The user-defined unique identifier of the clock. */ + identifier: userdata; + /** The clock against which to compare the timestamp. */ + clock_id: clockid; + /** The absolute or relative timestamp. */ + timeout: timestamp; + /** The amount of time that the implementation may wait additionally to coalesce with other events. */ + precision: timestamp; + /** Flags specifying whether the timeout is absolute or relative. */ + flags: subclockflags; + private __padding1: u32; + } + + /* Subscription to an event of type `eventtype.FD_READ` or `eventtype.FD_WRITE`.**/ + @unmanaged export class fdsubscription extends subscription { + /** The file descriptor on which to wait for it to become ready for reading or writing. */ + fd: fd; + } + + /** Timestamp in nanoseconds. */ + export type timestamp = u64; + + /** User-provided value that may be attached to objects that is retained when extracted from the implementation. */ + export type userdata = u64; + + /** The position relative to which to set the offset of the file descriptor. */ + export namespace whence { + /** Seek relative to current position. */ + // @ts-ignore: decorator + @inline + export const CUR: whence = 0; + /** Seek relative to end-of-file. */ + // @ts-ignore: decorator + @inline + export const END: whence = 1; + /** Seek relative to start-of-file. */ + // @ts-ignore: decorator + @inline + export const SET: whence = 2; + } + export type whence = u8; +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 784223a..c990fe7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,15 @@ { "extends": "./tsconfig.base.json", "compilerOptions": { - "typeRoots": ["./types"], - "types": ["assembly", "wasa", "as-pect"], + "typeRoots": [ + "./types" + ], + "types": [ + "assembly", + "wasa", + "as-pect", + "wasi" + ], "noLib": true, "alwaysStrict": true, "noImplicitAny": true, @@ -12,6 +19,11 @@ "strictNullChecks": true, "experimentalDecorators": true }, - "include": ["packages/*/assembly/**/*"], - "exclude": ["**/assemblyscript/src", "packages/**/node_modules/**/*"] -} + "include": [ + "packages/*/assembly/**/*" + ], + "exclude": [ + "**/assemblyscript/src", + "packages/**/node_modules/**/*" + ] +} \ No newline at end of file diff --git a/types/wasa/index.d.ts b/types/wasa/index.d.ts index b195512..af92942 100644 --- a/types/wasa/index.d.ts +++ b/types/wasa/index.d.ts @@ -1,3 +1,22 @@ + +declare class Ref{ + val: T; +} +declare class Tuple { + first: T1; + second: T2; +} +declare class WasiResult extends Tuple { + constructor(first: T | null, second?: Wasi.errno); + + failed: boolean; + error: Wasi.errno; + result: T; + static resolve(result: T): WasiResult; + static fail(err: Wasi.errno): WasiResult; + static void(res: Wasi.errno): WasiResult; +} + declare type fd = usize; declare type path = string; @@ -27,9 +46,14 @@ declare class Console { static error(s: string, newline?: boolean): void; static stdout: fd; - static stderr: fd; static stdin: fd; + static stderr: fd; } +// // declare const Cons: number; +// // declare function Cons1(): void; +// // declare type IO = wasa.IO; +declare function abort(): void; + declare class CommandLine { @@ -38,30 +62,79 @@ declare class CommandLine { static reset(): void; } -declare class Process { - static cwd: fd; - static exit(err: usize): void; +declare class FileDescriptor { + + file: File; + fd: u32; + offset: u32; + + write(bytes: Array): void; + + writeString(str: string): void; + + copyByte(ptr: usize): void; + + writeByte(byte: u8): void; + + read(bytes: Array): void; + + readByte(): u8; + + pread(bytes: Array): void; + + readString(): string; + + tell(): u32; + + + /** + * Resets the offset to 0 + */ + reset(): void; + + /** + * set seek (offset) + */ + seek(offset: usize): void; + + data: usize; } +declare class File { + static DefaultSize: u32; + data: usize; + grow(): File; +} -declare class fs { +declare class Directory extends File { + parent: Directory; + children: Array; +} + +declare class fs { /** * A simplified interface to open a file for read operations * @param path Path * @param dirfd Base directory descriptor (will be automatically set soon) */ - static openForRead(path: string, dirfd?: fd): fd; + static openForRead(path: string, dirfd?: fd): WasiResult; /** * A simplified interface to open a file for write operations * @param path Path * @param dirfd Base directory descriptor (will be automatically set soon) */ - static openForWrite(path: string, dirfd?: fd): fd; + static openForWrite(path: string, dirfd?: fd): WasiResult; - static openDirectory(path: string): fd; + static openDirectory(path: string, dirfd?: fd): WasiResult; + /** + * + * @param path path of new directory + * @param dirfd File fd for + */ + static createDirectory(path: string, dirfd?: fd): WasiResult; /** * Close a file descriptor @@ -74,7 +147,7 @@ declare class fs { * @param fd file descriptor * @param data data */ - static write(fd: fd, data: Array): void; + static write(fd: fd, data: Array): Wasi.errno; /** * Write a string to a file descriptor, after encoding it to UTF8 @@ -82,14 +155,14 @@ declare class fs { * @param s string * @param newline `true` to add a newline after the string */ - static writeString(fd: fd, s: string, newline?: bool): void; + static writeString(fd: fd, s: string, newline?: boolean): Wasi.errno; /** * Write a string to a file descriptor, after encoding it to UTF8, with a newline * @param fd file descriptor * @param s string */ - static writeStringLn(fd: fd, s: string): void; + static writeStringLn(fd: fd, s: string): Wasi.errno; /** * Read data from a file descriptor @@ -97,11 +170,7 @@ declare class fs { * @param data existing array to push data to * @param chunk_size chunk size (default: 4096) */ - static read( - fd: fd, - data?: Array, - chunk_size?: usize - ): Array | null; + static read(fd: fd, data: Array, chunk_size?: usize): Wasi.errno; /** * Read from a file descriptor until the end of the stream @@ -109,32 +178,44 @@ declare class fs { * @param data existing array to push data to * @param chunk_size chunk size (default: 4096) */ - static readAll( - fd: fd, - data?: Array, - chunk_size?: usize - ): Array | null; + static readAll(fd: fd, data: Array, chunk_size?: usize): Wasi.errno; /** * Read an UTF8 string from a file descriptor, convert it to a native string * @param fd file descriptor * @param chunk_size chunk size (default: 4096) */ - static readString(fd: fd, chunk_size?: usize): string; + static readString(fd: fd, chunk_size?: usize): WasiResult; /** * Reach an UTF8 String from a file descriptor until a new line is reached. */ - static readLine(fd: fd, chunk_size?: usize): string; + static readLine(fd: fd, chunk_size: usize): WasiResult; static reset(fd: fd): void; - - static erase(fd: fd): void; - /** * - * @param fd File Descriptor - * Returns the current offset of the file descriptor + * @param fd File fd + * returns the current offset of the file descriptor */ static tell(fd: fd): usize; + + /** + * + * @param fd File fd + * @param offset The number of bytes to move + * @param whence The base from which the offset is relative + */ + static seek(fd: fd, offset: Wasi.filedelta, whence?: Wasi.whence): WasiResult>; + + static get(fd: fd): WasiResult; + + static erase(fd: fd): void; + + +} + + +declare class Process { + static exit(code: number): void; } \ No newline at end of file diff --git a/types/wasi/index.d.ts b/types/wasi/index.d.ts new file mode 100644 index 0000000..88b8893 --- /dev/null +++ b/types/wasi/index.d.ts @@ -0,0 +1,1077 @@ + +// helper types to be more explicit +type char = u8; +type ptr = usize; // all pointers are usize'd +type struct = T; // structs are references already in AS + + + + +declare namespace Wasi { + + export interface Wasi { + /** Read command-line argument data. */ + args_get( + /** Input: Pointer to a buffer to write the argument pointers. */ + argv: ptr>, + /** Input: Pointer to a buffer to write the argument string data. */ + argv_buf: ptr + ): errno; + // + /** Return command-line argument data sizes. */ + args_sizes_get( + /** Output: Number of arguments. */ + argc: ptr, + /** Output: Size of the argument string data. */ + argv_buf_size: ptr + ): errno; + + /** Return the resolution of a clock. */ + clock_res_get( + /** Input: The clock for which to return the resolution. */ + clock: clockid, + /** Output: The resolution of the clock. */ + resolution: ptr + ): errno; + + /** Return the time value of a clock. */ + clock_time_get( + /** Input: Cock for which to return the time. */ + clock: clockid, + /** Input: Maximum lag (exclusive) that the returned time value may have, compared to its actual value. */ + precision: timestamp, + /** Output: Time value of the clock. */ + time: ptr + ): errno; + + /** Read environment variable data. */ + environ_get( + /** Input: Pointer to a buffer to write the environment variable pointers. */ + environ: ptr, + /** Input: Pointer to a buffer to write the environment variable string data. */ + environ_buf: usize + ): errno; + + /** Return command-line argument data sizes. */ + environ_sizes_get( + /** Output: The number of environment variables. */ + environ_count: ptr, + /** Output: The size of the environment variable string data. */ + environ_buf_size: ptr + ): errno; + + /** Provide file advisory information on a file descriptor. */ + fd_advise( + /** Input: The file descriptor for the file for which to provide file advisory information. */ + fd: fd, + /** Input: The offset within the file to which the advisory applies. */ + offset: filesize, + /** Input: The length of the region to which the advisory applies. */ + len: filesize, + /** Input: The advice. */ + advice: advice + ): errno; + + /** Provide file advisory information on a file descriptor. */ + fd_allocate( + /** Input: The file descriptor for the file in which to allocate space. */ + fd: fd, + /** Input: The offset at which to start the allocation. */ + offset: filesize, + /** Input: The length of the area that is allocated. */ + len: filesize + ): errno; + + /** Close a file descriptor. */ + fd_close( + /** Input: The file descriptor to close. */ + fd: fd + ): errno; + + /** Synchronize the data of a file to disk. */ + fd_datasync( + /** Input: The file descriptor of the file to synchronize to disk. */ + fd: fd + ): errno; + + /** Get the attributes of a file descriptor. */ + fd_fdstat_get( + /** Input: The file descriptor to inspect. */ + fd: fd, + /** Input: The buffer where the file descriptor's attributes are stored. */ + buf: struct + ): errno; + + /** Adjust the flags associated with a file descriptor. */ + fd_fdstat_set_flags( + /** Input: The file descriptor to operate on. */ + fd: fd, + /** Input: The desired values of the file descriptor flags. */ + flags: fdflags + ): errno; + + /** Adjust the rights associated with a file descriptor. */ + fd_fdstat_set_rights( + /** Input: The file descriptor to operate on. */ + fd: fd, + /** Input: The desired rights of the file descriptor. */ + fs_rights_base: rights, + /** Input: The desired rights of the file descriptor. */ + fs_rights_inheriting: rights + ): errno; + + /** Return the attributes of an open file. */ + fd_filestat_get( + /** Input: The file descriptor to inspect. */ + fd: fd, + /** Input: The buffer where the file's attributes are stored. */ + buf: struct + ): errno; + + /** Adjust the size of an open file. If this increases the file's size, the extra bytes are filled with zeros. */ + fd_filestat_set_size( + /** Input: A file descriptor for the file to adjust. */ + fd: fd, + /** Input: The desired file size. */ + size: filesize + ): errno; + + /** Adjust the timestamps of an open file or directory. */ + fd_filestat_set_times( + /** Input: The file descriptor to operate on. */ + fd: fd, + /** Input: The desired values of the data access timestamp. */ + st_atim: timestamp, + /** Input: The desired values of the data modification timestamp. */ + st_mtim: timestamp, + /** Input: A bitmask indicating which timestamps to adjust. */ + fstflags: fstflags + ): errno; + + /** Read from a file descriptor, without using and updating the file descriptor's offset. */ + fd_pread( + /** Input: The file descriptor from which to read data. */ + fd: fd, + /** Input: List of scatter/gather vectors in which to store data. */ + iovs: ptr>, + /** Input: Length of the list of scatter/gather vectors in which to store data. */ + iovs_len: usize, + /** Input: The offset within the file at which to read. */ + offset: filesize, + /** Output: The number of bytes read. */ + nread: ptr + ): errno; + + /** Return a description of the given preopened file descriptor. */ + fd_prestat_get( + /** Input: The file descriptor about which to retrieve information. */ + fd: fd, + /** Input: The buffer where the description is stored. */ + buf: struct + ): errno; + + /** Return a description of the given preopened file descriptor. */ + fd_prestat_dir_name( + /** Input: The file descriptor about which to retrieve information. */ + fd: fd, + /** Input: Buffer into which to write the preopened directory name. */ + path: ptr, + /** Input: Length of the buffer into which to write the preopened directory name. */ + path_len: usize + ): errno; + + /** Write to a file descriptor, without using and updating the file descriptor's offset. */ + fd_pwrite( + /** Input: The file descriptor to which to write data. */ + fd: fd, + /** Input: List of scatter/gather vectors from which to retrieve data. */ + iovs: ptr>, + /** Input: Length of the list of scatter/gather vectors from which to retrieve data. */ + iovs_len: usize, + /** Input: The offset within the file at which to write. */ + offset: filesize, + /** Output: The number of bytes written. */ + nwritten: ptr + ): errno; + + /** Read from a file descriptor. */ + fd_read( + /** Input: The file descriptor from which to read data. */ + fd: fd, + /** Input: List of scatter/gather vectors to which to store data. */ + iovs: ptr>, + /** Input: Length of the list of scatter/gather vectors to which to store data. */ + iovs_len: usize, + /** Output: The number of bytes read. */ + nread: ptr + ): errno; + + /** Read directory entries from a directory. */ + fd_readdir( + /** Input: Directory from which to read the directory entries. */ + fd: fd, + /** Input: Buffer where directory entries are stored. */ + buf: ptr>, + /** Input: Length of the buffer where directory entries are stored. */ + buf_len: usize, + /** Input: Location within the directory to start reading. */ + cookie: dircookie, + /** Output: Number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has been reached. */ + buf_used: ptr + ): errno; + + /** Atomically replace a file descriptor by renumbering another file descriptor. */ + fd_renumber( + /** Input: The file descriptor to renumber. */ + from: fd, + /** Input: The file descriptor to overwrite. */ + to: fd + ): errno; + + /** Move the offset of a file descriptor. */ + fd_seek( + /** Input: The file descriptor to operate on. */ + fd: fd, + /** Input: The number of bytes to move. */ + offset: filedelta, + /** Input: The base from which the offset is relative. */ + whence: whence, + /** Output: The new offset of the file descriptor, relative to the start of the file. */ + newoffset: ptr + ): errno; + + /** Synchronize the data and metadata of a file to disk. */ + fd_sync( + /** Input: The file descriptor of the file containing the data and metadata to synchronize to disk. */ + fd: fd + ): errno; + + /** Return the current offset of a file descriptor. */ + fd_tell( + /** Input: The file descriptor to inspect. */ + fd: fd, + /** Output: The current offset of the file descriptor, relative to the start of the file. */ + newoffset: ptr + ): errno; + + /** Write to a file descriptor. */ + fd_write( + /** Input: The file descriptor to which to write data. */ + fd: fd, + /** Input: List of scatter/gather vectors from which to retrieve data. */ + iovs: ptr>, + /** Input: List of scatter/gather vectors from which to retrieve data. */ + iovs_len: usize, + /** Output: The number of bytes written. */ + nwritten: ptr + ): errno; + + /* Create a directory. */ + path_create_directory( + /** Input: The working directory at which the resolution of the path starts. */ + fd: fd, + /** Input: The path at which to create the directory. */ + path: ptr, + /** Input: The path at which to create the directory. */ + path_len: usize + ): errno; + + /** Return the attributes of a file or directory. */ + path_filestat_get( + /** Input: The working directory at which the resolution of the path starts. */ + fd: fd, + /** Input: Flags determining the method of how the path is resolved. */ + flags: lookupflags, + /** Input: The path of the file or directory to inspect. */ + path: ptr, + /** Input: The path of the file or directory to inspect. */ + path_len: usize, + /** Input: The buffer where the file's attributes are stored. */ + buf: struct + ): errno; + + /** Adjust the timestamps of a file or directory. */ + path_filestat_set_times( + /** Input: The working directory at which the resolution of the path starts. */ + fd: fd, + /** Input: Flags determining the method of how the path is resolved. */ + flags: lookupflags, + /** Input: The path of the file or directory to operate on. */ + path: ptr, + /** Input: The path of the file or directory to operate on. */ + path_len: usize, + /** Input: The desired values of the data access timestamp. */ + st_atim: timestamp, + /** Input: The desired values of the data modification timestamp. */ + st_mtim: timestamp, + /** Input: A bitmask indicating which timestamps to adjust. */ + fstflags: fstflags + ): errno; + + /** Create a hard link. */ + path_link( + /** Input: The working directory at which the resolution of the old path starts. */ + old_fd: fd, + /** Input: Flags determining the method of how the path is resolved. */ + old_flags: lookupflags, + /** Input: The source path from which to link. */ + old_path: ptr, + /** Input: The source path from which to link. */ + old_path_len: usize, + /** Input: The working directory at which the resolution of the new path starts. */ + new_fd: fd, + /** Input: The destination path at which to create the hard link. */ + new_path: ptr, + /** Input: The length of the destination path at which to create the hard link. */ + new_path_len: usize + ): errno; + + /** Open a file or directory. */ + path_open( + /** Input: The working directory at which the resolution of the path starts. */ + dirfd: fd, + /** Input: Flags determining the method of how the path is resolved. */ + dirflags: lookupflags, + /** Input: The path of the file or directory to open. */ + path: ptr, + /** Input: The length of the path of the file or directory to open. */ + path_len: usize, + /** Input: The method by which to open the file. */ + oflags: oflags, + /** Input: The initial base rights that apply to operations using the file descriptor itself. */ + fs_rights_base: rights, + /** Input: The initial inheriting rights that apply to file descriptors derived from it. */ + fs_rights_inheriting: rights, + /** Input: The initial flags of the file descriptor. */ + fs_flags: fdflags, + /** Output: The file descriptor of the file that has been opened. */ + fd: ptr + ): errno; + + /** Read the contents of a symbolic link. */ + path_readlink( + /** Input: The working directory at which the resolution of the path starts. */ + fd: fd, + /** Input: The path of the symbolic link from which to read. */ + path: ptr, + /** Input: The length of the path of the symbolic link from which to read. */ + path_len: usize, + /** Input: The buffer to which to write the contents of the symbolic link. */ + buf: ptr, + /** Input: The length of the buffer to which to write the contents of the symbolic link. */ + buf_len: usize, + /** Output: The number of bytes placed in the buffer. */ + buf_used: ptr + ): errno; + + /** Remove a directory. */ + path_remove_directory( + /** Input: The working directory at which the resolution of the path starts. */ + fd: fd, + /** Input: The path to a directory to remove. */ + path: ptr, + /** Input: The length of the path to a directory to remove. */ + path_len: usize + ): errno; + + /** Rename a file or directory. */ + path_rename( + /** Input: The working directory at which the resolution of the old path starts. */ + old_fd: fd, + /** Input: The source path of the file or directory to rename. */ + old_path: ptr, + /** Input: The length of the source path of the file or directory to rename. */ + old_path_len: usize, + /** Input: The working directory at which the resolution of the new path starts. */ + new_fd: fd, + /** Input: The destination path to which to rename the file or directory. */ + new_path: ptr, + /** Input: The length of the destination path to which to rename the file or directory. */ + new_path_len: usize + ): errno; + + /** Create a symbolic link. */ + path_symlink( + /** Input: The contents of the symbolic link. */ + old_path: ptr, + /** Input: The length of the contents of the symbolic link. */ + old_path_len: usize, + /** Input: The working directory at which the resolution of the path starts. */ + fd: fd, + /** Input: The destination path at which to create the symbolic link. */ + new_path: ptr, + /** Input: The length of the destination path at which to create the symbolic link. */ + new_path_len: usize + ): errno; + + /** Unlink a file. */ + path_unlink_file( + /** Input: The working directory at which the resolution of the path starts. */ + fd: fd, + /** Input: The path to a file to unlink. */ + path: ptr, + /** Input: The length of the path to a file to unlink. */ + path_len: usize + ): errno; + + /** Concurrently poll for the occurrence of a set of events. */ + poll_oneoff( + /** Input: The events to which to subscribe. */ + in_: ptr>, + /** Input: The events that have occurred. */ + out: ptr>, + /** Input: Both the number of subscriptions and events. */ + nsubscriptions: usize, + /** Output: The number of events stored. */ + nevents: ptr + ): errno; + + /** Terminate the process normally. An exit code of 0 indicates successful termination of the program. The meanings of other values is dependent on the environment. */ + proc_exit( + /** Input: The exit code returned by the process. */ + rval: u32 + ): void; + + /** Send a signal to the process of the calling thread. */ + proc_raise( + /** Input: The signal condition to trigger. */ + sig: signal + ): errno; + + /** Write high-quality random data into a buffer. */ + random_get( + /** Input: The buffer to fill with random data. */ + buf: usize, + /** Input: The length of the buffer to fill with random data. */ + buf_len: usize + ): errno; + + /** Temporarily yield execution of the calling thread. */ + sched_yield(): errno; + + /** Receive a message from a socket. */ + sock_recv( + /** Input: The socket on which to receive data. */ + sock: fd, + /** Input: List of scatter/gather vectors to which to store data. */ + ri_data: ptr>, + /** Input: The length of the list of scatter/gather vectors to which to store data. */ + ri_data_len: usize, + /** Input: Message flags. */ + ri_flags: riflags, + /** Output: Number of bytes stored in `ri_data`. */ + ro_datalen: ptr, + /** Output: Message flags. */ + ro_flags: ptr + ): errno; + + /** Send a message on a socket. */ + sock_send( + /** Input: The socket on which to send data. */ + sock: fd, + /** Input: List of scatter/gather vectors to which to retrieve data */ + si_data: ptr>, + /** Input: The length of the list of scatter/gather vectors to which to retrieve data */ + si_data_len: usize, + /** Input: Message flags. */ + si_flags: siflags, + /** Output: Number of bytes transmitted. */ + so_datalen: ptr + ): errno; + + /** Shut down socket send and receive channels. */ + sock_shutdown( + /** Input: The socket on which to shutdown channels. */ + sock: fd, + /** Input: Which channels on the socket to shut down. */ + how: sdflags + ): errno; + } + + // === Types ====================================================================================== + + export const ExitSuccess = 0; + + /** File or memory access pattern advisory information. */ + export enum advice { + /** The application has no advice to give on its behavior with respect to the specified data. */ + NORMAL = 0, + // /** The application expects to access the specified data sequentially from lower offsets to higher offsets. */ + SEQUENTIAL = 1, + // /** The application expects to access the specified data in a random order. */ + RANDOM = 2, + // /** The application expects to access the specified data in the near future. */ + WILLNEED = 3, + // /** The application expects that it will not access the specified data in the near future. */ + DONTNEED = 4, + // /** The application expects to access the specified data once and then not reuse it thereafter. */ + NOREUSE = 5, + } + + /** Identifiers for clocks. */ + export enum clockid { + /** The clock measuring real time. Time value zero corresponds with 1970-01-01T00:00:00Z. */ + REALTIME = 0, + // /** The store-wide monotonic clock. Absolute value has no meaning. */ + MONOTONIC = 1, + // /** The CPU-time clock associated with the current process. */ + PROCESS_CPUTIME_ID = 2, + // /** The CPU-time clock associated with the current thread. */ + THREAD_CPUTIME_ID = 3, + } + + /** Identifier for a device containing a file system. Can be used in combination with `inode` to uniquely identify a file or directory in the filesystem. */ + export type device = u64; + + /** A reference to the offset of a directory entry. */ + export type dircookie = u64; + + /** A directory entry. */ + export class dirent { + /** The offset of the next directory entry stored in this directory. */ + next: dircookie; + /** The serial number of the file referred to by this directory entry. */ + ino: inode; + /** The length of the name of the directory entry. */ + namlen: u32; + /** The type of the file referred to by this directory entry. */ + type: filetype; + private __padding0: u16; + } + + /** Error codes returned by functions. */ + export enum errno { + /** No error occurred. System call completed successfully. */ + SUCCESS = 0, + /** Argument list too long. */ + TOOBIG = 1, + /** Permission denied. */ + ACCES = 2, + /** Address in use. */ + ADDRINUSE = 3, + /** Address not available. */ + ADDRNOTAVAIL = 4, + /** Address family not supported. */ + AFNOSUPPORT = 5, + /** Resource unavailable, or operation would block. */ + AGAIN = 6, + /** Connection already in progress. */ + ALREADY = 7, + /** Bad file descriptor. */ + BADF = 8, + /** Bad message. */ + BADMSG = 9, + /** Device or resource busy. */ + BUSY = 10, + /** Operation canceled. */ + CANCELED = 11, + /** No child processes. */ + CHILD = 12, + /** Connection aborted. */ + CONNABORTED = 13, + /** Connection refused. */ + CONNREFUSED = 14, + /** Connection reset. */ + CONNRESET = 15, + /** Resource deadlock would occur. */ + DEADLK = 16, + /** Destination address required. */ + DESTADDRREQ = 17, + /** Mathematics argument out of domain of function. */ + DOM = 18, + /** Reserved. */ + DQUOT = 19, + /** File exists. */ + EXIST = 20, + /** Bad address. */ + FAULT = 21, + /** File too large. */ + FBIG = 22, + /** Host is unreachable. */ + HOSTUNREACH = 23, + /** Identifier removed. */ + IDRM = 24, + /** Illegal byte sequence. */ + ILSEQ = 25, + /** Operation in progress. */ + INPROGRESS = 26, + /** Interrupted function. */ + INTR = 27, + /** Invalid argument. */ + INVAL = 28, + /** I/O error. */ + IO = 29, + /** Socket is connected. */ + ISCONN = 30, + /** Is a directory. */ + ISDIR = 31, + /** Too many levels of symbolic links. */ + LOOP = 32, + /** File descriptor value too large. */ + MFILE = 33, + /** Too many links. */ + MLINK = 34, + /** Message too large. */ + MSGSIZE = 35, + /** Reserved. */ + MULTIHOP = 36, + /** Filename too long. */ + NAMETOOLONG = 37, + /** Network is down. */ + NETDOWN = 38, + /** Connection aborted by network. */ + NETRESET = 39, + /** Network unreachable. */ + NETUNREACH = 40, + /** Too many files open in system. */ + NFILE = 41, + /** No buffer space available. */ + NOBUFS = 42, + /** No such device. */ + NODEV = 43, + /** No such file or directory. */ + NOENT = 44, + /** Executable file format error. */ + NOEXEC = 45, + /** No locks available. */ + NOLCK = 46, + /** Reserved. */ + NOLINK = 47, + /** Not enough space. */ + NOMEM = 48, + /** No message of the desired type. */ + NOMSG = 49, + /** Protocol not available. */ + NOPROTOOPT = 50, + /** No space left on device. */ + NOSPC = 51, + /** Function not supported. */ + NOSYS = 52, + /** The socket is not connected. */ + NOTCONN = 53, + /** Not a directory or a symbolic link to a directory. */ + NOTDIR = 54, + /** Directory not empty. */ + NOTEMPTY = 55, + /** State not recoverable. */ + NOTRECOVERABLE = 56, + /** Not a socket. */ + NOTSOCK = 57, + /** Not supported, or operation not supported on socket. */ + NOTSUP = 58, + /** Inappropriate I/O control operation. */ + NOTTY = 59, + /** No such device or address. */ + NXIO = 60, + /** Value too large to be stored in data type. */ + OVERFLOW = 61, + /** Previous owner died. */ + OWNERDEAD = 62, + /** Operation not permitted. */ + PERM = 63, + /** Broken pipe. */ + PIPE = 64, + /** Protocol error. */ + PROTO = 65, + /** Protocol not supported. */ + PROTONOSUPPORT = 66, + /** Protocol wrong type for socket. */ + PROTOTYPE = 67, + /** Result too large. */ + RANGE = 68, + /** Read-only file system. */ + ROFS = 69, + /** Invalid seek. */ + SPIPE = 70, + /** No such process. */ + SRCH = 71, + /** Reserved. */ + STALE = 72, + /** Connection timed out. */ + TIMEDOUT = 73, + /** Text file busy. */ + TXTBSY = 74, + /** Cross-device link. */ + XDEV = 75, + /** Extension: Capabilities insufficient. */ + NOTCAPABLE = 76, + } + // + /** An event that occurred. */ + export class event { + /** User-provided value that got attached to `subscription#userdata`. */ + userdata: userdata; + /** If non-zero, an error that occurred while processing the subscription request. */ + error: errno; + /* The type of the event that occurred. */ + type: eventtype; + private __padding0: u16; + } + // + /** An event that occurred when type is `eventtype.FD_READ` or `eventtype.FD_WRITE`. */ + export class rwevent extends event { + /* The number of bytes available for reading or writing. */ + nbytes: filesize; + /* The state of the file descriptor. */ + flags: eventrwflags; + private __padding1: u32; + } + // + /** The state of the file descriptor subscribed to with `eventtype.FD_READ` or `eventtype.FD_WRITE`. */ + export enum eventrwflags { + /** The peer of this socket has closed or disconnected. */ + HANGUP = 1, + } + + /** Type of a subscription to an event or its occurrence. */ + export enum eventtype { + /** The time value of clock has reached the timestamp. */ + CLOCK = 0, + /** File descriptor has data available for reading. */ + FD_READ = 1, + // /** File descriptor has capacity available for writing */ + FD_WRITE = 2, + } + // export type eventtype = u8; + // + // /** Exit code generated by a process when exiting. */ + // export type exitcode = u32; + // + // /** A file descriptor number. */ + export type fd = u32; + // + // /** File descriptor flags. */ + export enum fdflags { + /** Append mode: Data written to the file is always appended to the file's end. */ + APPEND = 1, + /** Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized. */ + DSYNC = 2, + /** Non-blocking mode. */ + NONBLOCK = 4, + /** Synchronized read I/O operations. */ + RSYNC = 8, + /** Write according to synchronized I/O file integrity completion. */ + SYNC = 16, + } + + /** File descriptor attributes. */ + export class fdstat { + /** File type. */ + filetype: filetype; + /** File descriptor flags. */ + flags: fdflags; + /** Rights that apply to this file descriptor. */ + rights_base: rights; + /** Maximum set of rights that may be installed on new file descriptors that are created through this file descriptor, e.g., through `path_open`. */ + rights_inheriting: rights; + } + + /** Relative offset within a file. */ + export type filedelta = i64; + // + // /** Non-negative file size or length of a region within a file. */ + export type filesize = u64; + + /** File attributes. */ + export class filestat { + /** Device ID of device containing the file. */ + dev: device; + /** File serial number. */ + ino: inode; + /** File type. */ + filetype: filetype; + /** Number of hard links to the file. */ + nlink: linkcount; + /** For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. */ + size: filesize; + /** Last data access timestamp. */ + atim: timestamp; + /** Last data modification timestamp. */ + mtim: timestamp; + /** Last file status change timestamp. */ + ctim: timestamp; + } + + /** The type of a file descriptor or file. */ + export enum filetype { + /** The type of the file descriptor or file is unknown or is different from any of the other types specified. */ + UNKNOWN = 0, + /** The file descriptor or file refers to a block device inode. */ + BLOCK_DEVICE = 1, + /** The file descriptor or file refers to a character device inode. */ + CHARACTER_DEVICE = 2, + /** The file descriptor or file refers to a directory inode. */ + DIRECTORY = 3, + /** The file descriptor or file refers to a regular file inode. */ + REGULAR_FILE = 4, + /** The file descriptor or file refers to a datagram socket. */ + SOCKET_DGRAM = 5, + /** The file descriptor or file refers to a byte-stream socket. */ + SOCKET_STREAM = 6, + /** The file refers to a symbolic link inode. */ + SYMBOLIC_LINK = 7, + } + + /** Which file time attributes to adjust. */ + export enum fstflags { + /** Adjust the last data access timestamp to the value stored in `filestat#st_atim`. */ + SET_ATIM = 1, + /** Adjust the last data access timestamp to the time of clock `clockid.REALTIME`. */ + SET_ATIM_NOW = 2, + /** Adjust the last data modification timestamp to the value stored in `filestat#st_mtim`. */ + SET_MTIM = 4, + /** Adjust the last data modification timestamp to the time of clock `clockid.REALTIME`. */ + SET_MTIM_NOW = 8, + } + + + /** File serial number that is unique within its file system. */ + export type inode = u64; + + /** A region of memory for scatter/gather reads. */ + export class iovec { + /** The address of the buffer to be filled. */ + buf: usize; + /** The length of the buffer to be filled. */ + buf_len: usize; + } + + /** Number of hard links to an inode. */ + export type linkcount = u32; + + /** Flags determining the method of how paths are resolved. */ + export enum lookupflags { + /** As long as the resolved path corresponds to a symbolic link, it is expanded. */ + SYMLINK_FOLLOW = 1, + } + + /** Open flags. */ + export enum oflags { + /** Create file if it does not exist. */ + CREAT = 1, + /** Fail if not a directory. */ + DIRECTORY = 2, + /** Fail if file already exists. */ + EXCL = 4, + /** Truncate file to size 0. */ + TRUNC = 8, + } + + // TODO: undocumented + export enum preopentype { + DIR = 0, + } + + // TODO: undocumented + export abstract class prestat { + type: preopentype; + } + + // TODO: undocumented + export class dirprestat extends prestat { + name_len: usize; + } + + /** Flags provided to `sock_recv`. */ + export enum riflags { + /** Returns the message without removing it from the socket's receive queue. */ + PEEK = 1, + /** On byte-stream sockets, block until the full amount of data can be returned. */ + WAITALL = 2, + } + + /** File descriptor rights, determining which actions may be performed. */ + export enum rights { + /** The right to invoke `fd_datasync`. */ + FD_DATASYNC = 1, + /** The right to invoke `fd_read` and `sock_recv`. */ + FD_READ = 2, + /** The right to invoke `fd_seek`. This flag implies `rights.FD_TELL`. */ + FD_SEEK = 4, + /** The right to invoke `fd_fdstat_set_flags`. */ + FD_FDSTAT_SET_FLAGS = 8, + /** The right to invoke `fd_sync`. */ + FD_SYNC = 16, + /** The right to invoke `fd_seek` in such a way that the file offset remains unaltered (i.e., `whence.CUR` with offset zero), or to invoke `fd_tell`). */ + FD_TELL = 32, + /** The right to invoke `fd_write` and `sock_send`. If `rights.FD_SEEK` is set, includes the right to invoke `fd_pwrite`. */ + FD_WRITE = 64, + /** The right to invoke `fd_advise`. */ + FD_ADVISE = 128, + /** The right to invoke `fd_allocate`. */ + FD_ALLOCATE = 256, + /** The right to invoke `path_create_directory`. */ + PATH_CREATE_DIRECTORY = 512, + /** If `rights.PATH_OPEN` is set, the right to invoke `path_open` with `oflags.CREAT`. */ + PATH_CREATE_FILE = 1024, + /** The right to invoke `path_link` with the file descriptor as the source directory. */ + PATH_LINK_SOURCE = 2048, + /** The right to invoke `path_link` with the file descriptor as the target directory. */ + PATH_LINK_TARGET = 4096, + /** The right to invoke `path_open`. */ + PATH_OPEN = 8192, + /** The right to invoke `fd_readdir`. */ + FD_READDIR = 16384, + /** The right to invoke `path_readlink`. */ + PATH_READLINK = 32768, + /** The right to invoke `path_rename` with the file descriptor as the source directory. */ + PATH_RENAME_SOURCE = 65536, + /** The right to invoke `path_rename` with the file descriptor as the target directory. */ + PATH_RENAME_TARGET = 131072, + /** The right to invoke `path_filestat_get`. */ + PATH_FILESTAT_GET = 262144, + /** The right to change a file's size (there is no `path_filestat_set_size`). If `rights.PATH_OPEN` is set, includes the right to invoke `path_open` with `oflags.TRUNC`. */ + PATH_FILESTAT_SET_SIZE = 524288, + /** The right to invoke `path_filestat_set_times`. */ + PATH_FILESTAT_SET_TIMES = 1048576, + /** The right to invoke `fd_filestat_get`. */ + FD_FILESTAT_GET = 2097152, + /** The right to invoke `fd_filestat_set_size`. */ + FD_FILESTAT_SET_SIZE = 4194304, + /** The right to invoke `fd_filestat_set_times`. */ + FD_FILESTAT_SET_TIMES = 8388608, + /** The right to invoke `path_symlink`. */ + RIGHT_PATH_SYMLINK = 16777216, + /** The right to invoke `path_remove_directory`. */ + PATH_REMOVE_DIRECTORY = 33554432, + /** The right to invoke `path_unlink_file`. */ + PATH_UNLINK_FILE = 67108864, + /** If `rights.FD_READ` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype.FD_READ`. If `rights.FD_WRITE` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype.FD_WRITE`. */ + POLL_FD_READWRITE = 134217728, + /** The right to invoke `sock_shutdown`. */ + SOCK_SHUTDOWN = 268435456, + } + + /** Flags returned by `sock_recv`. */ + export enum roflags { + /** Message data has been truncated. */ + DATA_TRUNCATED = 1, + } + + /** Which channels on a socket to shut down. */ + export enum sdflags { + /** Disables further receive operations. */ + RD = 1, + /** Disables further send operations. */ + WR = 2, + } + + + /** Flags provided to `sock_send`. */ + export enum siflags { + // As there are currently no flags defined, it must be set to zero. + } + + + /** Signal condition. */ + export enum signal { + /** Hangup. */ + HUP = 1, + /** Terminate interrupt signal. */ + INT = 2, + /** Terminal quit signal. */ + QUIT = 3, + /** Illegal instruction. */ + ILL = 4, + /** Trace/breakpoint trap. */ + TRAP = 5, + /** Process abort signal. */ + ABRT = 6, + /** Access to an undefined portion of a memory object. */ + BUS = 7, + /** Erroneous arithmetic operation. */ + FPE = 8, + /** Kill. */ + KILL = 9, + /** User-defined signal 1. */ + USR1 = 10, + /** Invalid memory reference. */ + SEGV = 11, + /** User-defined signal 2. */ + USR2 = 12, + /** Write on a pipe with no one to read it. */ + PIPE = 13, + /** Alarm clock. */ + ALRM = 14, + /** Termination signal. */ + TERM = 15, + /** Child process terminated, stopped, or continued. */ + CHLD = 16, + /** Continue executing, if stopped. */ + CONT = 17, + /** Stop executing. */ + STOP = 18, + /** Terminal stop signal. */ + TSTP = 19, + /** Background process attempting read. */ + TTIN = 20, + /** Background process attempting write. */ + TTOU = 21, + /** High bandwidth data is available at a socket. */ + URG = 22, + /** CPU time limit exceeded. */ + XCPU = 23, + /** File size limit exceeded. */ + XFSZ = 24, + /** Virtual timer expired. */ + VTALRM = 25, + PROF = 26, + WINCH = 27, + POLL = 28, + PWR = 29, + /** Bad system call. */ + SYS = 30, + } + + /** Flags determining how to interpret the timestamp provided in `subscription_t::u.clock.timeout. */ + export enum subclockflags { + /** If set, treat the timestamp provided in `clocksubscription` as an absolute timestamp. */ + ABSTIME = 1 + } + + /** Subscription to an event. */ + export abstract class subscription { + /** User-provided value that is attached to the subscription. */ + userdata: userdata; + /** The type of the event to which to subscribe. */ + type: eventtype; + private __padding0: u32; + } + + /* Subscription to an event of type `eventtype.CLOCK`.**/ + export class clocksubscription extends subscription { + /** The user-defined unique identifier of the clock. */ + identifier: userdata; + /** The clock against which to compare the timestamp. */ + clock_id: clockid; + /** The absolute or relative timestamp. */ + timeout: timestamp; + /** The amount of time that the implementation may wait additionally to coalesce with other events. */ + precision: timestamp; + /** Flags specifying whether the timeout is absolute or relative. */ + flags: subclockflags; + private __padding1: u32; + } + + /* Subscription to an event of type `eventtype.FD_READ` or `eventtype.FD_WRITE`.**/ + export class fdsubscription extends subscription { + /** The file descriptor on which to wait for it to become ready for reading or writing. */ + fd: fd; + } + + /** Timestamp in nanoseconds. */ + export type timestamp = u64; + + /** User-provided value that may be attached to objects that is retained when extracted from the implementation. */ + export type userdata = u64; + + /** The position relative to which to set the offset of the file descriptor. */ + export enum whence { + /** Seek relative to current position. */ + CUR = 0, + /** Seek relative to end-of-file. */ + END = 1, + /** Seek relative to start-of-file. */ + SET = 2, + } +}