diff options
Diffstat (limited to 'js')
-rw-r--r-- | js/deno.ts | 2 | ||||
-rw-r--r-- | js/files.ts | 25 | ||||
-rw-r--r-- | js/files_test.ts | 64 | ||||
-rw-r--r-- | js/io.ts | 10 |
4 files changed, 89 insertions, 12 deletions
diff --git a/js/deno.ts b/js/deno.ts index 6d6e57a41..490494cc6 100644 --- a/js/deno.ts +++ b/js/deno.ts @@ -11,6 +11,7 @@ export { stderr, read, write, + seek, close, OpenMode } from "./files"; @@ -18,6 +19,7 @@ export { copy, toAsyncIterator, ReadResult, + SeekMode, Reader, Writer, Closer, diff --git a/js/files.ts b/js/files.ts index e2c7123e6..a77f788df 100644 --- a/js/files.ts +++ b/js/files.ts @@ -1,12 +1,12 @@ // Copyright 2018-2019 the Deno authors. All rights reserved. MIT license. -import { Reader, Writer, Closer, ReadResult } from "./io"; +import { Reader, Writer, Seeker, Closer, ReadResult, SeekMode } from "./io"; import * as dispatch from "./dispatch"; import * as msg from "gen/msg_generated"; import { assert } from "./util"; import * as flatbuffers from "./flatbuffers"; /** The Deno abstraction for reading and writing files. */ -export class File implements Reader, Writer, Closer { +export class File implements Reader, Writer, Seeker, Closer { constructor(readonly rid: number) {} write(p: Uint8Array): Promise<number> { @@ -17,6 +17,10 @@ export class File implements Reader, Writer, Closer { return read(this.rid, p); } + seek(offset: number, whence: SeekMode): Promise<void> { + return seek(this.rid, offset, whence); + } + close(): void { close(this.rid); } @@ -123,6 +127,23 @@ export async function write(rid: number, p: Uint8Array): Promise<number> { return res.nbyte(); } +/** Seek a file ID to the given offset under mode given by `whence`. + * + */ +export async function seek( + rid: number, + offset: number, + whence: SeekMode +): Promise<void> { + const builder = flatbuffers.createBuilder(); + msg.Seek.startSeek(builder); + msg.Seek.addRid(builder, rid); + msg.Seek.addOffset(builder, offset); + msg.Seek.addWhence(builder, whence); + const inner = msg.Seek.endSeek(builder); + await dispatch.sendAsync(builder, msg.Any.Seek, inner); +} + /** Close the file ID. */ export function close(rid: number): void { const builder = flatbuffers.createBuilder(); diff --git a/js/files_test.ts b/js/files_test.ts index 6698f85c3..5d23cff52 100644 --- a/js/files_test.ts +++ b/js/files_test.ts @@ -141,15 +141,61 @@ testPerm({ read: true, write: true }, async function openModeWriteRead() { fileInfo = Deno.statSync(filename); assertEqual(fileInfo.len, 13); - // TODO: this test is not working, I expect because - // file handle points to the end of file, but ATM - // deno has no seek implementation on Rust side - // assert file can be read - // const buf = new Uint8Array(20); - // const result = await file.read(buf); - // console.log(result.eof, result.nread); - // assertEqual(result.nread, 13); - // file.close(); + const buf = new Uint8Array(20); + await file.seek(0, Deno.SeekMode.SEEK_START); + const result = await file.read(buf); + assertEqual(result.nread, 13); + file.close(); await Deno.remove(tempDir, { recursive: true }); }); + +testPerm({ read: true }, async function seekStart() { + const filename = "tests/hello.txt"; + const file = await Deno.open(filename); + // Deliberately move 1 step forward + await file.read(new Uint8Array(1)); // "H" + // Skipping "Hello " + await file.seek(6, Deno.SeekMode.SEEK_START); + const buf = new Uint8Array(6); + await file.read(buf); + const decoded = new TextDecoder().decode(buf); + assertEqual(decoded, "world!"); +}); + +testPerm({ read: true }, async function seekCurrent() { + const filename = "tests/hello.txt"; + const file = await Deno.open(filename); + // Deliberately move 1 step forward + await file.read(new Uint8Array(1)); // "H" + // Skipping "ello " + await file.seek(5, Deno.SeekMode.SEEK_CURRENT); + const buf = new Uint8Array(6); + await file.read(buf); + const decoded = new TextDecoder().decode(buf); + assertEqual(decoded, "world!"); +}); + +testPerm({ read: true }, async function seekEnd() { + const filename = "tests/hello.txt"; + const file = await Deno.open(filename); + await file.seek(-6, Deno.SeekMode.SEEK_END); + const buf = new Uint8Array(6); + await file.read(buf); + const decoded = new TextDecoder().decode(buf); + assertEqual(decoded, "world!"); +}); + +testPerm({ read: true }, async function seekMode() { + const filename = "tests/hello.txt"; + const file = await Deno.open(filename); + let err; + try { + await file.seek(1, -1); + } catch (e) { + err = e; + } + assert(!!err); + assertEqual(err.kind, Deno.ErrorKind.InvalidSeekMode); + assertEqual(err.name, "InvalidSeekMode"); +}); @@ -9,6 +9,14 @@ export interface ReadResult { eof: boolean; } +// Seek whence values. +// https://golang.org/pkg/io/#pkg-constants +export enum SeekMode { + SEEK_START = 0, + SEEK_CURRENT = 1, + SEEK_END = 2 +} + // Reader is the interface that wraps the basic read() method. // https://golang.org/pkg/io/#Reader export interface Reader { @@ -74,7 +82,7 @@ export interface Seeker { * any positive offset is legal, but the behavior of subsequent I/O operations * on the underlying object is implementation-dependent. */ - seek(offset: number, whence: number): Promise<void>; + seek(offset: number, whence: SeekMode): Promise<void>; } // https://golang.org/pkg/io/#ReadCloser |