diff --git a/packages/ash/assembly/__tests__/echo.spec.ts b/packages/ash/assembly/__tests__/echo.spec.ts index e15896e..533e1a0 100644 --- a/packages/ash/assembly/__tests__/echo.spec.ts +++ b/packages/ash/assembly/__tests__/echo.spec.ts @@ -17,12 +17,12 @@ describe("echo", (): void => { echo(CommandLine.all()) let str = Hello + " " + World + "\n"; let stdoutStr = readString(stdout) - expect(Console.stdout.tell()).toBe(str.lengthUTF8, "Two extra characters for space and \\n") + expect(Console.stdout.tell()).toBe(str.lengthUTF8) Console.stdout.reset(); expect(readString(Console.stdout)).toBe(Hello + " " + World + "\n") Console.stdout.reset(); expect(readString(Console.stdout)).toBe(stdoutStr); - }) + }); it("should print no newline with -n", () => { CommandLine.push("-n") @@ -30,7 +30,7 @@ describe("echo", (): void => { 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") + expect(Console.stdout.tell()).toBe(str.lengthUTF8) Console.stdout.reset(); expect(Console.stdout.readString().result).toBe(str) Console.stdout.reset(); diff --git a/packages/assemblyscript/assembly/__tests__/wasa.spec.ts b/packages/assemblyscript/assembly/__tests__/wasa.spec.ts index 303f915..1c2d293 100644 --- a/packages/assemblyscript/assembly/__tests__/wasa.spec.ts +++ b/packages/assemblyscript/assembly/__tests__/wasa.spec.ts @@ -52,10 +52,16 @@ describe("readLine", (): void => { expect(StringUtils.fromCStringTilNewLine(utfStr, str.lengthUTF8)).toStrictEqual("Hello\n") }); - it("should read return null after no more lines", (): void => { + it("should read null when reading from a terminating char", (): void => { let str = "Hello World"; let utfStr = str.toUTF8(); - expect(StringUtils.fromCStringTilNewLine(utfStr, str.lengthUTF8 - 2)).toBeNull(); + expect(StringUtils.fromCStringTilNewLine(utfStr + str.lengthUTF8, str.lengthUTF8)).toBeNull(); + }); + + it("should read chunk", () => { + let hello = "Hello "; + let world = hello + "World"; + expect(StringUtils.fromCString(world.toUTF8(), hello.lengthUTF8)).toStrictEqual(hello); }); }); @@ -86,3 +92,35 @@ describe("Open", (): void => { }); }); + +describe("read", (): void => { + it("read string should return error if offset is at the eof", () => { + let file = _fs.createFile("./tmp"); + file.result.erase(); + expect(file.result.readString().error).toBe(Wasi.errno.NOMEM); + }); +}) + +let file: FileDescriptor; +describe("write", (): void => { + + beforeEach(() => { + file = _fs.createFile("./tmp").result; + file.erase(); + }); + + it("should update size after a write", () => { + expect(file.size).toBe(0); + let str = "hello world"; + expect(file.writeString("hello world")).toBe(Wasi.errno.SUCCESS) + expect(file.size).toBe(str.lengthUTF8); + }); + + it("should not update size if offset is less than size", (): void => { + let str = "hello world"; + expect(file.writeString("hello world")).toBe(Wasi.errno.SUCCESS) + file.reset(); + expect(file.writeString("HELLO")).toBe(Wasi.errno.SUCCESS) + expect(file.size).toBe(str.lengthUTF8); + }) +}) diff --git a/packages/assemblyscript/assembly/wasa/mock/fs/fs.ts b/packages/assemblyscript/assembly/wasa/mock/fs/fs.ts index 8206af6..e2bf0dc 100644 --- a/packages/assemblyscript/assembly/wasa/mock/fs/fs.ts +++ b/packages/assemblyscript/assembly/wasa/mock/fs/fs.ts @@ -15,25 +15,24 @@ export class FileDescriptor { constructor(public fd: fd, public file: File | null, public offset: usize = 0) { } write(bytes: Array): Wasi.errno { - if (bytes.length + this.offset > this.length) { - return Wasi.errno.NOMEM + let res = this.file!.writeBytes(this.offset, bytes.buffer_.data, bytes.length); + if (res == Wasi.errno.SUCCESS) { + this.offset += bytes.length; } - memory.copy(this.data + this.offset, bytes.buffer_.data, bytes.length) - this.offset += bytes.length; - return Wasi.errno.SUCCESS; + return res; } writeString(str: string, newline: boolean = false): Wasi.errno { // TODO: Add error checking let _str = str + (newline ? "\n" : ""); - if (_str.lengthUTF8 as usize + this.offset > this.length) { - return Wasi.errno.NOMEM + let res = this.file!.writeBytes(this.offset, _str.toUTF8(), _str.lengthUTF8); + if (res == Wasi.errno.SUCCESS) { + this.offset += _str.lengthUTF8; } - memory.copy(this.data + this.offset, _str.toUTF8(), _str.lengthUTF8); - this.offset += str.lengthUTF8 + 1; - return Wasi.errno.SUCCESS; + return res; } + read(bytes: Array): Wasi.errno { if (!this.hasSpace(bytes)) { return Wasi.errno.NOMEM; @@ -57,16 +56,19 @@ export class FileDescriptor { } readString(max: usize = 4096): WasiResult { - let str = StringUtils.fromCString(this.data + this.offset, this.length - this.offset); + let _max = Math.min(max, this.length - this.offset); + let str = StringUtils.fromCString(this.data + this.offset, _max); + log(str); if (str == null) { return WasiResult.fail(Wasi.errno.NOMEM) } - this.offset += str.lengthUTF8 + 1; //For null character + this.offset += str.lengthUTF8; //For null character return WasiResult.resolve(str); } - readLine(): WasiResult { - let str = StringUtils.fromCStringTilNewLine(this.data + this.offset, this.length - this.offset); + readLine(max: usize = 4096): WasiResult { + let _max = Math.min(max, this.length - this.offset); + let str = StringUtils.fromCStringTilNewLine(this.data + this.offset, _max); if (str == null) { return WasiResult.fail(Wasi.errno.NOMEM) } @@ -92,7 +94,7 @@ export class FileDescriptor { break; } case Wasi.whence.END: { - newOffset = (this.length - Math.abs(offset)); + newOffset = (this.size - Math.abs(offset)); break; } case Wasi.whence.SET: { @@ -147,6 +149,11 @@ export class FileDescriptor { } return Wasi.errno.NOMEM; } + + get size(): usize { + return this.file!.size; + } + } export class DirectoryDescriptor extends FileDescriptor { @@ -162,7 +169,8 @@ export class DirectoryDescriptor extends FileDescriptor { listDir(): DirectoryEntry[] { let files = new Array(); for (let i: i32 = 0; i < this.children.length; i++) { - files.push(new DirectoryEntry(path.basename(this.children[i].path), this.children[i].type)) + let child = this.children[i]; + files.push(new DirectoryEntry(path.basename(child.path), child.type, child.size)) } return files; } @@ -175,8 +183,11 @@ export class DirectoryDescriptor extends FileDescriptor { export class File { private _data: ArrayBuffer; static DefaultSize: u32 = 1024; + size: usize = 0; + constructor(public path: string, public type: Wasi.filetype = Wasi.filetype.REGULAR_FILE) { this._data = new ArrayBuffer(File.DefaultSize); + this.writeEOT(0); } /** * @@ -206,6 +217,8 @@ export class File { erase(): Wasi.errno { this._data = new ArrayBuffer(File.DefaultSize); + this.size = 0; + this.writeEOT(0); return Wasi.errno.SUCCESS; } @@ -213,6 +226,31 @@ export class File { return this._data.byteLength; } + writeEOT(offset: usize): Wasi.errno { + return this.writeByte(offset, StringUtils.EOT); + } + + writeByte(offset: usize, byte: u8): Wasi.errno { + if (offset >= this.length) { + return Wasi.errno.NOMEM; + } + store(this.data + offset, byte); + return Wasi.errno.SUCCESS; + } + + writeBytes(offset: usize, ptr: usize, size: usize): Wasi.errno { + if (offset + size >= this.length) { + return Wasi.errno.NOMEM; + } + let dst = offset + this.data; + memory.copy(dst, ptr, size); + if (offset + size > this.size) { + this.size = offset + size; + this.writeEOT(this.size); + } + return Wasi.errno.SUCCESS; + } + stat: Wasi.filestat } @@ -229,7 +267,7 @@ class Directory extends File { } class DirectoryEntry { - constructor(public path: string, public type: Wasi.filetype) { } + constructor(public path: string, public type: Wasi.filetype, public size: usize) { } } @@ -374,12 +412,12 @@ export class FileSystem { return res.result.read(data); } - readString(fd: fd, offset: usize = 0): WasiResult { + readString(fd: fd, max?: usize): WasiResult { let res = this.get(fd); if (res.failed) { return WasiResult.fail(res.error); } - return res.result.readString(); + return res.result.readString(max); } readline(fd: fd, max?: usize): WasiResult { @@ -387,7 +425,7 @@ export class FileSystem { if (res.failed) { return WasiResult.fail(res.error); } - return res.result.readLine(); + return res.result.readLine(max); } writeString(fd: fd, data: string, newline: boolean): Wasi.errno { diff --git a/packages/assemblyscript/assembly/wasa/mock/utils/index.ts b/packages/assemblyscript/assembly/wasa/mock/utils/index.ts index d06f287..cde6f02 100644 --- a/packages/assemblyscript/assembly/wasa/mock/utils/index.ts +++ b/packages/assemblyscript/assembly/wasa/mock/utils/index.ts @@ -1,33 +1,41 @@ -const newLine: u8 = 10; export class StringUtils { - static isNewLine(ptr: usize): boolean { - return load(ptr) == newLine; - } + static readonly NUL: u8 = 0; + static readonly EOT: u8 = 4; + static readonly LF: u8 = 10; - static fromCString(cstring: usize, max: usize = 4096): string | null { - let size: usize = 0; - while (load(cstring + size) != 0 && size < max) { - size++; + static isNewLine(ptr: usize): boolean { + return load(ptr) == this.LF; } - if (size >= max && load(cstring + size) != 0) { - return null; + + private static terminates(ptr: usize): bool { + let char: u8 = load(ptr); + return char == this.NUL || char == this.EOT } - return String.fromUTF8(cstring, size); - } - static fromCStringTilNewLine(cstring: usize, max: usize): string | null { - let size: usize = 0; - while (load(cstring + size) != 0 && size < max) { - size++; - if (this.isNewLine(cstring + size - 1)) { - break; - } + static fromCString(cstring: usize, max: usize = 4096): string | null { + let size: usize = 0; + while (!this.terminates(cstring + size) && size < max - 1) { + size++; + } + if (size == 0) { + return null + } + return String.fromUTF8(cstring, size); } - if (size >= max && load(cstring + size) != 0) { - return null; + + static fromCStringTilNewLine(cstring: usize, max: usize): string | null { + let size: usize = 0; + while (!this.terminates(cstring + size) && size < max - 1) { + size++; + if (this.isNewLine(cstring + size - 1)) { + break; + } + } + if (size == 0) { + return null + } + return String.fromUTF8(cstring, size); } - return String.fromUTF8(cstring, size); - } } \ No newline at end of file diff --git a/types/wasa/index.d.ts b/types/wasa/index.d.ts index 833c1dd..a65d5e2 100644 --- a/types/wasa/index.d.ts +++ b/types/wasa/index.d.ts @@ -84,6 +84,10 @@ declare class FileDescriptor { file: File | null; fd: u32; offset: u32; + /** + * Number of bytes written to the file. + */ + size: usize; /** * Write an array of bytes to a file; @@ -152,7 +156,7 @@ declare class DirectoryDescriptor extends FileDescriptor { /** * Returns list of names of entries in the directory. */ - listDir(): string[]; + listDir(): DirectoryEntry[]; /**Path of parent directory */ parent: string; @@ -342,6 +346,7 @@ declare class fs { declare class DirectoryEntry { path: string; type: Wasi.filetype; + size: usize; } /**