mirror of
https://github.com/denoland/deno.git
synced 2024-11-24 15:19:26 -05:00
parent
d0b6152f11
commit
597ee38ef2
10 changed files with 337 additions and 190 deletions
21
cli/msg.fbs
21
cli/msg.fbs
|
@ -39,8 +39,6 @@ union Any {
|
|||
Read,
|
||||
ReadDir,
|
||||
ReadDirRes,
|
||||
ReadFile,
|
||||
ReadFileRes,
|
||||
ReadRes,
|
||||
Readlink,
|
||||
ReadlinkRes,
|
||||
|
@ -69,7 +67,6 @@ union Any {
|
|||
WorkerGetMessageRes,
|
||||
WorkerPostMessage,
|
||||
Write,
|
||||
WriteFile,
|
||||
WriteRes,
|
||||
}
|
||||
|
||||
|
@ -296,14 +293,6 @@ table Remove {
|
|||
recursive: bool;
|
||||
}
|
||||
|
||||
table ReadFile {
|
||||
filename: string;
|
||||
}
|
||||
|
||||
table ReadFileRes {
|
||||
data: [ubyte];
|
||||
}
|
||||
|
||||
table ReadDir {
|
||||
path: string;
|
||||
}
|
||||
|
@ -312,16 +301,6 @@ table ReadDirRes {
|
|||
entries: [StatRes];
|
||||
}
|
||||
|
||||
table WriteFile {
|
||||
filename: string;
|
||||
data: [ubyte];
|
||||
update_perm: bool;
|
||||
perm: uint;
|
||||
// perm specified by https://godoc.org/os#FileMode
|
||||
is_create: bool;
|
||||
is_append: bool;
|
||||
}
|
||||
|
||||
table CopyFile {
|
||||
from: string;
|
||||
to: string;
|
||||
|
|
71
cli/ops.rs
71
cli/ops.rs
|
@ -174,7 +174,6 @@ pub fn op_selector_std(inner_type: msg::Any) -> Option<OpCreator> {
|
|||
msg::Any::Permissions => Some(op_permissions),
|
||||
msg::Any::Read => Some(op_read),
|
||||
msg::Any::ReadDir => Some(op_read_dir),
|
||||
msg::Any::ReadFile => Some(op_read_file),
|
||||
msg::Any::Readlink => Some(op_read_link),
|
||||
msg::Any::Remove => Some(op_remove),
|
||||
msg::Any::Rename => Some(op_rename),
|
||||
|
@ -193,7 +192,6 @@ pub fn op_selector_std(inner_type: msg::Any) -> Option<OpCreator> {
|
|||
msg::Any::WorkerGetMessage => Some(op_worker_get_message),
|
||||
msg::Any::WorkerPostMessage => Some(op_worker_post_message),
|
||||
msg::Any::Write => Some(op_write),
|
||||
msg::Any::WriteFile => Some(op_write_file),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -1026,45 +1024,6 @@ fn op_remove(
|
|||
})
|
||||
}
|
||||
|
||||
// Prototype https://github.com/denoland/deno/blob/golang/os.go#L171-L184
|
||||
fn op_read_file(
|
||||
sc: &IsolateStateContainer,
|
||||
base: &msg::Base<'_>,
|
||||
data: deno_buf,
|
||||
) -> Box<OpWithError> {
|
||||
assert_eq!(data.len(), 0);
|
||||
let inner = base.inner_as_read_file().unwrap();
|
||||
let cmd_id = base.cmd_id();
|
||||
let filename_ = inner.filename().unwrap();
|
||||
let filename = PathBuf::from(filename_);
|
||||
debug!("op_read_file {}", filename.display());
|
||||
if let Err(e) = sc.state().check_read(&filename_) {
|
||||
return odd_future(e);
|
||||
}
|
||||
blocking(base.sync(), move || {
|
||||
let vec = fs::read(&filename)?;
|
||||
// Build the response message. memcpy data into inner.
|
||||
// TODO(ry) zero-copy.
|
||||
let builder = &mut FlatBufferBuilder::new();
|
||||
let data_off = builder.create_vector(vec.as_slice());
|
||||
let inner = msg::ReadFileRes::create(
|
||||
builder,
|
||||
&msg::ReadFileResArgs {
|
||||
data: Some(data_off),
|
||||
},
|
||||
);
|
||||
Ok(serialize_response(
|
||||
cmd_id,
|
||||
builder,
|
||||
msg::BaseArgs {
|
||||
inner: Some(inner.as_union_value()),
|
||||
inner_type: msg::Any::ReadFileRes,
|
||||
..Default::default()
|
||||
},
|
||||
))
|
||||
})
|
||||
}
|
||||
|
||||
fn op_copy_file(
|
||||
sc: &IsolateStateContainer,
|
||||
base: &msg::Base<'_>,
|
||||
|
@ -1260,36 +1219,6 @@ fn op_read_dir(
|
|||
})
|
||||
}
|
||||
|
||||
fn op_write_file(
|
||||
sc: &IsolateStateContainer,
|
||||
base: &msg::Base<'_>,
|
||||
data: deno_buf,
|
||||
) -> Box<OpWithError> {
|
||||
let inner = base.inner_as_write_file().unwrap();
|
||||
let filename = String::from(inner.filename().unwrap());
|
||||
let update_perm = inner.update_perm();
|
||||
let perm = inner.perm();
|
||||
let is_create = inner.is_create();
|
||||
let is_append = inner.is_append();
|
||||
|
||||
if let Err(e) = sc.state().check_write(&filename) {
|
||||
return odd_future(e);
|
||||
}
|
||||
|
||||
blocking(base.sync(), move || -> OpResult {
|
||||
debug!("op_write_file {} {}", filename, data.len());
|
||||
deno_fs::write_file_2(
|
||||
Path::new(&filename),
|
||||
data,
|
||||
update_perm,
|
||||
perm,
|
||||
is_create,
|
||||
is_append,
|
||||
)?;
|
||||
Ok(empty_buf())
|
||||
})
|
||||
}
|
||||
|
||||
fn op_rename(
|
||||
sc: &IsolateStateContainer,
|
||||
base: &msg::Base<'_>,
|
||||
|
|
49
js/buffer.ts
49
js/buffer.ts
|
@ -5,7 +5,7 @@
|
|||
// https://github.com/golang/go/blob/master/LICENSE
|
||||
|
||||
//import * as io from "./io";
|
||||
import { Reader, Writer, ReadResult } from "./io";
|
||||
import { Reader, Writer, ReadResult, SyncReader, SyncWriter } from "./io";
|
||||
import { assert } from "./util";
|
||||
import { TextDecoder } from "./text_encoding";
|
||||
import { DenoError, ErrorKind } from "./errors";
|
||||
|
@ -32,7 +32,7 @@ function copyBytes(dst: Uint8Array, src: Uint8Array, off = 0): number {
|
|||
/** A Buffer is a variable-sized buffer of bytes with read() and write()
|
||||
* methods. Based on https://golang.org/pkg/bytes/#Buffer
|
||||
*/
|
||||
export class Buffer implements Reader, Writer {
|
||||
export class Buffer implements Reader, SyncReader, Writer, SyncWriter {
|
||||
private buf: Uint8Array; // contents are the bytes buf[off : len(buf)]
|
||||
private off = 0; // read at buf[off], write at buf[buf.byteLength]
|
||||
|
||||
|
@ -126,11 +126,11 @@ export class Buffer implements Reader, Writer {
|
|||
this.buf = new Uint8Array(this.buf.buffer, 0, len);
|
||||
}
|
||||
|
||||
/** read() reads the next len(p) bytes from the buffer or until the buffer
|
||||
/** readSync() reads the next len(p) bytes from the buffer or until the buffer
|
||||
* is drained. The return value n is the number of bytes read. If the
|
||||
* buffer has no data to return, eof in the response will be true.
|
||||
*/
|
||||
async read(p: Uint8Array): Promise<ReadResult> {
|
||||
readSync(p: Uint8Array): ReadResult {
|
||||
if (this.empty()) {
|
||||
// Buffer is empty, reset to recover space.
|
||||
this.reset();
|
||||
|
@ -145,11 +145,21 @@ export class Buffer implements Reader, Writer {
|
|||
return { nread, eof: false };
|
||||
}
|
||||
|
||||
async write(p: Uint8Array): Promise<number> {
|
||||
async read(p: Uint8Array): Promise<ReadResult> {
|
||||
const rr = this.readSync(p);
|
||||
return Promise.resolve(rr);
|
||||
}
|
||||
|
||||
writeSync(p: Uint8Array): number {
|
||||
const m = this._grow(p.byteLength);
|
||||
return copyBytes(this.buf, p, m);
|
||||
}
|
||||
|
||||
async write(p: Uint8Array): Promise<number> {
|
||||
const n = this.writeSync(p);
|
||||
return Promise.resolve(n);
|
||||
}
|
||||
|
||||
/** _grow() grows the buffer to guarantee space for n more bytes.
|
||||
* It returns the index where bytes should be written.
|
||||
* If the buffer can't grow it will throw with ErrTooLarge.
|
||||
|
@ -226,6 +236,27 @@ export class Buffer implements Reader, Writer {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Sync version of `readFrom`
|
||||
*/
|
||||
readFromSync(r: SyncReader): number {
|
||||
let n = 0;
|
||||
while (true) {
|
||||
try {
|
||||
const i = this._grow(MIN_READ);
|
||||
this._reslice(i);
|
||||
const fub = new Uint8Array(this.buf.buffer, i);
|
||||
const { nread, eof } = r.readSync(fub);
|
||||
this._reslice(i + nread);
|
||||
n += nread;
|
||||
if (eof) {
|
||||
return n;
|
||||
}
|
||||
} catch (e) {
|
||||
return n;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Read `r` until EOF and return the content as `Uint8Array`.
|
||||
|
@ -235,3 +266,11 @@ export async function readAll(r: Reader): Promise<Uint8Array> {
|
|||
await buf.readFrom(r);
|
||||
return buf.bytes();
|
||||
}
|
||||
|
||||
/** Read synchronously `r` until EOF and return the content as `Uint8Array`.
|
||||
*/
|
||||
export function readAllSync(r: SyncReader): Uint8Array {
|
||||
const buf = new Buffer();
|
||||
buf.readFromSync(r);
|
||||
return buf.bytes();
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
// https://github.com/golang/go/blob/master/LICENSE
|
||||
import { assertEquals, test } from "./test_util.ts";
|
||||
|
||||
const { Buffer, readAll } = Deno;
|
||||
const { Buffer, readAll, readAllSync } = Deno;
|
||||
type Buffer = Deno.Buffer;
|
||||
|
||||
// N controls how many iterations of certain checks are performed.
|
||||
|
@ -193,6 +193,23 @@ test(async function bufferReadFrom() {
|
|||
}
|
||||
});
|
||||
|
||||
test(async function bufferReadFromSync() {
|
||||
init();
|
||||
const buf = new Buffer();
|
||||
for (let i = 3; i < 30; i += 3) {
|
||||
const s = await fillBytes(
|
||||
buf,
|
||||
"",
|
||||
5,
|
||||
testBytes.subarray(0, Math.floor(testBytes.byteLength / i))
|
||||
);
|
||||
const b = new Buffer();
|
||||
b.readFromSync(buf);
|
||||
const fub = new Uint8Array(testString.length);
|
||||
await empty(b, s, fub);
|
||||
}
|
||||
});
|
||||
|
||||
test(async function bufferTestGrow() {
|
||||
const tmp = new Uint8Array(72);
|
||||
for (let startLen of [0, 100, 1000, 10000, 100000]) {
|
||||
|
@ -226,3 +243,13 @@ test(async function testReadAll() {
|
|||
assertEquals(testBytes[i], actualBytes[i]);
|
||||
}
|
||||
});
|
||||
|
||||
test(function testReadAllSync() {
|
||||
init();
|
||||
const reader = new Buffer(testBytes.buffer as ArrayBuffer);
|
||||
const actualBytes = readAllSync(reader);
|
||||
assertEquals(testBytes.byteLength, actualBytes.byteLength);
|
||||
for (let i = 0; i < testBytes.length; ++i) {
|
||||
assertEquals(testBytes[i], actualBytes[i]);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -6,12 +6,16 @@ export { chdir, cwd } from "./dir";
|
|||
export {
|
||||
File,
|
||||
open,
|
||||
openSync,
|
||||
stdin,
|
||||
stdout,
|
||||
stderr,
|
||||
read,
|
||||
readSync,
|
||||
write,
|
||||
writeSync,
|
||||
seek,
|
||||
seekSync,
|
||||
close,
|
||||
OpenMode
|
||||
} from "./files";
|
||||
|
@ -21,9 +25,12 @@ export {
|
|||
ReadResult,
|
||||
SeekMode,
|
||||
Reader,
|
||||
SyncReader,
|
||||
Writer,
|
||||
SyncWriter,
|
||||
Closer,
|
||||
Seeker,
|
||||
SyncSeeker,
|
||||
ReadCloser,
|
||||
WriteCloser,
|
||||
ReadSeeker,
|
||||
|
@ -31,7 +38,7 @@ export {
|
|||
ReadWriteCloser,
|
||||
ReadWriteSeeker
|
||||
} from "./io";
|
||||
export { Buffer, readAll } from "./buffer";
|
||||
export { Buffer, readAll, readAllSync } from "./buffer";
|
||||
export { mkdirSync, mkdir } from "./mkdir";
|
||||
export {
|
||||
makeTempDirSync,
|
||||
|
|
194
js/files.ts
194
js/files.ts
|
@ -1,10 +1,53 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
import { Reader, Writer, Seeker, Closer, ReadResult, SeekMode } from "./io";
|
||||
import {
|
||||
Reader,
|
||||
Writer,
|
||||
Seeker,
|
||||
Closer,
|
||||
ReadResult,
|
||||
SeekMode,
|
||||
SyncReader,
|
||||
SyncWriter,
|
||||
SyncSeeker
|
||||
} from "./io";
|
||||
import * as dispatch from "./dispatch";
|
||||
import * as msg from "gen/msg_generated";
|
||||
import { assert } from "./util";
|
||||
import * as flatbuffers from "./flatbuffers";
|
||||
|
||||
function reqOpen(
|
||||
filename: string,
|
||||
mode: OpenMode
|
||||
): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] {
|
||||
const builder = flatbuffers.createBuilder();
|
||||
const filename_ = builder.createString(filename);
|
||||
const mode_ = builder.createString(mode);
|
||||
msg.Open.startOpen(builder);
|
||||
msg.Open.addFilename(builder, filename_);
|
||||
msg.Open.addMode(builder, mode_);
|
||||
const inner = msg.Open.endOpen(builder);
|
||||
return [builder, msg.Any.Open, inner];
|
||||
}
|
||||
|
||||
function resOpen(baseRes: null | msg.Base): File {
|
||||
assert(baseRes != null);
|
||||
assert(msg.Any.OpenRes === baseRes!.innerType());
|
||||
const res = new msg.OpenRes();
|
||||
assert(baseRes!.inner(res) != null);
|
||||
const rid = res.rid();
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
return new File(rid);
|
||||
}
|
||||
|
||||
/** Open a file and return an instance of the `File` object
|
||||
* synchronously.
|
||||
*
|
||||
* const file = Deno.openSync("/foo/bar.txt");
|
||||
*/
|
||||
export function openSync(filename: string, mode: OpenMode = "r"): File {
|
||||
return resOpen(dispatch.sendSync(...reqOpen(filename, mode)));
|
||||
}
|
||||
|
||||
/** Open a file and return an instance of the `File` object.
|
||||
*
|
||||
* (async () => {
|
||||
|
@ -15,33 +58,21 @@ export async function open(
|
|||
filename: string,
|
||||
mode: OpenMode = "r"
|
||||
): Promise<File> {
|
||||
const builder = flatbuffers.createBuilder();
|
||||
const filename_ = builder.createString(filename);
|
||||
const mode_ = builder.createString(mode);
|
||||
msg.Open.startOpen(builder);
|
||||
msg.Open.addFilename(builder, filename_);
|
||||
msg.Open.addMode(builder, mode_);
|
||||
const inner = msg.Open.endOpen(builder);
|
||||
const baseRes = await dispatch.sendAsync(builder, msg.Any.Open, inner);
|
||||
assert(baseRes != null);
|
||||
assert(msg.Any.OpenRes === baseRes!.innerType());
|
||||
const res = new msg.OpenRes();
|
||||
assert(baseRes!.inner(res) != null);
|
||||
const rid = res.rid();
|
||||
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
||||
return new File(rid);
|
||||
return resOpen(await dispatch.sendAsync(...reqOpen(filename, mode)));
|
||||
}
|
||||
|
||||
/** Read from a file ID into an array buffer.
|
||||
*
|
||||
* Resolves with the `ReadResult` for the operation.
|
||||
*/
|
||||
export async function read(rid: number, p: Uint8Array): Promise<ReadResult> {
|
||||
function reqRead(
|
||||
rid: number,
|
||||
p: Uint8Array
|
||||
): [flatbuffers.Builder, msg.Any, flatbuffers.Offset, Uint8Array] {
|
||||
const builder = flatbuffers.createBuilder();
|
||||
msg.Read.startRead(builder);
|
||||
msg.Read.addRid(builder, rid);
|
||||
const inner = msg.Read.endRead(builder);
|
||||
const baseRes = await dispatch.sendAsync(builder, msg.Any.Read, inner, p);
|
||||
return [builder, msg.Any.Read, inner, p];
|
||||
}
|
||||
|
||||
function resRead(baseRes: null | msg.Base): ReadResult {
|
||||
assert(baseRes != null);
|
||||
assert(msg.Any.ReadRes === baseRes!.innerType());
|
||||
const res = new msg.ReadRes();
|
||||
|
@ -49,16 +80,47 @@ export async function read(rid: number, p: Uint8Array): Promise<ReadResult> {
|
|||
return { nread: res.nread(), eof: res.eof() };
|
||||
}
|
||||
|
||||
/** Write to the file ID the contents of the array buffer.
|
||||
/** Read synchronously from a file ID into an array buffer.
|
||||
*
|
||||
* Return `ReadResult` for the operation.
|
||||
*
|
||||
* const file = Deno.openSync("/foo/bar.txt");
|
||||
* const buf = new Uint8Array(100);
|
||||
* const { nread, eof } = Deno.readSync(file.rid, buf);
|
||||
* const text = new TextDecoder.decode(buf);
|
||||
*
|
||||
* Resolves with the number of bytes written.
|
||||
*/
|
||||
export async function write(rid: number, p: Uint8Array): Promise<number> {
|
||||
export function readSync(rid: number, p: Uint8Array): ReadResult {
|
||||
return resRead(dispatch.sendSync(...reqRead(rid, p)));
|
||||
}
|
||||
|
||||
/** Read from a file ID into an array buffer.
|
||||
*
|
||||
* Resolves with the `ReadResult` for the operation.
|
||||
*
|
||||
* (async () => {
|
||||
* const file = await Deno.open("/foo/bar.txt");
|
||||
* const buf = new Uint8Array(100);
|
||||
* const { nread, eof } = await Deno.read(file.rid, buf);
|
||||
* const text = new TextDecoder.decode(buf);
|
||||
* })();
|
||||
*/
|
||||
export async function read(rid: number, p: Uint8Array): Promise<ReadResult> {
|
||||
return resRead(await dispatch.sendAsync(...reqRead(rid, p)));
|
||||
}
|
||||
|
||||
function reqWrite(
|
||||
rid: number,
|
||||
p: Uint8Array
|
||||
): [flatbuffers.Builder, msg.Any, flatbuffers.Offset, Uint8Array] {
|
||||
const builder = flatbuffers.createBuilder();
|
||||
msg.Write.startWrite(builder);
|
||||
msg.Write.addRid(builder, rid);
|
||||
const inner = msg.Write.endWrite(builder);
|
||||
const baseRes = await dispatch.sendAsync(builder, msg.Any.Write, inner, p);
|
||||
return [builder, msg.Any.Write, inner, p];
|
||||
}
|
||||
|
||||
function resWrite(baseRes: null | msg.Base): number {
|
||||
assert(baseRes != null);
|
||||
assert(msg.Any.WriteRes === baseRes!.innerType());
|
||||
const res = new msg.WriteRes();
|
||||
|
@ -66,21 +128,71 @@ 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`.
|
||||
/** Write synchronously to the file ID the contents of the array buffer.
|
||||
*
|
||||
* Resolves with the number of bytes written.
|
||||
*
|
||||
* const encoder = new TextEncoder();
|
||||
* const data = encoder.encode("Hello world\n");
|
||||
* const file = Deno.openSync("/foo/bar.txt");
|
||||
* Deno.writeSync(file.rid, data);
|
||||
*/
|
||||
export function writeSync(rid: number, p: Uint8Array): number {
|
||||
return resWrite(dispatch.sendSync(...reqWrite(rid, p)));
|
||||
}
|
||||
|
||||
/** Write to the file ID the contents of the array buffer.
|
||||
*
|
||||
* Resolves with the number of bytes written.
|
||||
*
|
||||
* (async () => {
|
||||
* const encoder = new TextEncoder();
|
||||
* const data = encoder.encode("Hello world\n");
|
||||
* const file = await Deno.open("/foo/bar.txt");
|
||||
* await Deno.write(file.rid, data);
|
||||
* })();
|
||||
*
|
||||
*/
|
||||
export async function seek(
|
||||
export async function write(rid: number, p: Uint8Array): Promise<number> {
|
||||
return resWrite(await dispatch.sendAsync(...reqWrite(rid, p)));
|
||||
}
|
||||
|
||||
function reqSeek(
|
||||
rid: number,
|
||||
offset: number,
|
||||
whence: SeekMode
|
||||
): Promise<void> {
|
||||
): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] {
|
||||
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);
|
||||
return [builder, msg.Any.Seek, inner];
|
||||
}
|
||||
|
||||
/** Seek a file ID synchronously to the given offset under mode given by `whence`.
|
||||
*
|
||||
* const file = Deno.openSync("/foo/bar.txt");
|
||||
* Deno.seekSync(file.rid, 0, 0);
|
||||
*/
|
||||
export function seekSync(rid: number, offset: number, whence: SeekMode): void {
|
||||
dispatch.sendSync(...reqSeek(rid, offset, whence));
|
||||
}
|
||||
|
||||
/** Seek a file ID to the given offset under mode given by `whence`.
|
||||
*
|
||||
* (async () => {
|
||||
* const file = await Deno.open("/foo/bar.txt");
|
||||
* await Deno.seek(file.rid, 0, 0);
|
||||
* })();
|
||||
*/
|
||||
export async function seek(
|
||||
rid: number,
|
||||
offset: number,
|
||||
whence: SeekMode
|
||||
): Promise<void> {
|
||||
await dispatch.sendAsync(...reqSeek(rid, offset, whence));
|
||||
}
|
||||
|
||||
/** Close the file ID. */
|
||||
|
@ -93,21 +205,41 @@ export function close(rid: number): void {
|
|||
}
|
||||
|
||||
/** The Deno abstraction for reading and writing files. */
|
||||
export class File implements Reader, Writer, Seeker, Closer {
|
||||
export class File
|
||||
implements
|
||||
Reader,
|
||||
SyncReader,
|
||||
Writer,
|
||||
SyncWriter,
|
||||
Seeker,
|
||||
SyncSeeker,
|
||||
Closer {
|
||||
constructor(readonly rid: number) {}
|
||||
|
||||
write(p: Uint8Array): Promise<number> {
|
||||
return write(this.rid, p);
|
||||
}
|
||||
|
||||
writeSync(p: Uint8Array): number {
|
||||
return writeSync(this.rid, p);
|
||||
}
|
||||
|
||||
read(p: Uint8Array): Promise<ReadResult> {
|
||||
return read(this.rid, p);
|
||||
}
|
||||
|
||||
readSync(p: Uint8Array): ReadResult {
|
||||
return readSync(this.rid, p);
|
||||
}
|
||||
|
||||
seek(offset: number, whence: SeekMode): Promise<void> {
|
||||
return seek(this.rid, offset, whence);
|
||||
}
|
||||
|
||||
seekSync(offset: number, whence: SeekMode): void {
|
||||
return seekSync(this.rid, offset, whence);
|
||||
}
|
||||
|
||||
close(): void {
|
||||
close(this.rid);
|
||||
}
|
||||
|
|
|
@ -163,6 +163,19 @@ testPerm({ read: true }, async function seekStart() {
|
|||
assertEquals(decoded, "world!");
|
||||
});
|
||||
|
||||
testPerm({ read: true }, function seekSyncStart() {
|
||||
const filename = "tests/hello.txt";
|
||||
const file = Deno.openSync(filename);
|
||||
// Deliberately move 1 step forward
|
||||
file.readSync(new Uint8Array(1)); // "H"
|
||||
// Skipping "Hello "
|
||||
file.seekSync(6, Deno.SeekMode.SEEK_START);
|
||||
const buf = new Uint8Array(6);
|
||||
file.readSync(buf);
|
||||
const decoded = new TextDecoder().decode(buf);
|
||||
assertEquals(decoded, "world!");
|
||||
});
|
||||
|
||||
testPerm({ read: true }, async function seekCurrent() {
|
||||
const filename = "tests/hello.txt";
|
||||
const file = await Deno.open(filename);
|
||||
|
@ -176,6 +189,19 @@ testPerm({ read: true }, async function seekCurrent() {
|
|||
assertEquals(decoded, "world!");
|
||||
});
|
||||
|
||||
testPerm({ read: true }, function seekSyncCurrent() {
|
||||
const filename = "tests/hello.txt";
|
||||
const file = Deno.openSync(filename);
|
||||
// Deliberately move 1 step forward
|
||||
file.readSync(new Uint8Array(1)); // "H"
|
||||
// Skipping "ello "
|
||||
file.seekSync(5, Deno.SeekMode.SEEK_CURRENT);
|
||||
const buf = new Uint8Array(6);
|
||||
file.readSync(buf);
|
||||
const decoded = new TextDecoder().decode(buf);
|
||||
assertEquals(decoded, "world!");
|
||||
});
|
||||
|
||||
testPerm({ read: true }, async function seekEnd() {
|
||||
const filename = "tests/hello.txt";
|
||||
const file = await Deno.open(filename);
|
||||
|
@ -186,6 +212,16 @@ testPerm({ read: true }, async function seekEnd() {
|
|||
assertEquals(decoded, "world!");
|
||||
});
|
||||
|
||||
testPerm({ read: true }, function seekSyncEnd() {
|
||||
const filename = "tests/hello.txt";
|
||||
const file = Deno.openSync(filename);
|
||||
file.seekSync(-6, Deno.SeekMode.SEEK_END);
|
||||
const buf = new Uint8Array(6);
|
||||
file.readSync(buf);
|
||||
const decoded = new TextDecoder().decode(buf);
|
||||
assertEquals(decoded, "world!");
|
||||
});
|
||||
|
||||
testPerm({ read: true }, async function seekMode() {
|
||||
const filename = "tests/hello.txt";
|
||||
const file = await Deno.open(filename);
|
||||
|
|
11
js/io.ts
11
js/io.ts
|
@ -49,6 +49,10 @@ export interface Reader {
|
|||
read(p: Uint8Array): Promise<ReadResult>;
|
||||
}
|
||||
|
||||
export interface SyncReader {
|
||||
readSync(p: Uint8Array): ReadResult;
|
||||
}
|
||||
|
||||
// Writer is the interface that wraps the basic write() method.
|
||||
// https://golang.org/pkg/io/#Writer
|
||||
export interface Writer {
|
||||
|
@ -63,6 +67,9 @@ export interface Writer {
|
|||
write(p: Uint8Array): Promise<number>;
|
||||
}
|
||||
|
||||
export interface SyncWriter {
|
||||
writeSync(p: Uint8Array): number;
|
||||
}
|
||||
// https://golang.org/pkg/io/#Closer
|
||||
export interface Closer {
|
||||
// The behavior of Close after the first call is undefined. Specific
|
||||
|
@ -85,6 +92,10 @@ export interface Seeker {
|
|||
seek(offset: number, whence: SeekMode): Promise<void>;
|
||||
}
|
||||
|
||||
export interface SyncSeeker {
|
||||
seekSync(offset: number, whence: SeekMode): void;
|
||||
}
|
||||
|
||||
// https://golang.org/pkg/io/#ReadCloser
|
||||
export interface ReadCloser extends Reader, Closer {}
|
||||
|
||||
|
|
|
@ -1,29 +1,6 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
import * as msg from "gen/msg_generated";
|
||||
import * as flatbuffers from "./flatbuffers";
|
||||
import { assert } from "./util";
|
||||
import * as dispatch from "./dispatch";
|
||||
|
||||
function req(
|
||||
filename: string
|
||||
): [flatbuffers.Builder, msg.Any, flatbuffers.Offset] {
|
||||
const builder = flatbuffers.createBuilder();
|
||||
const filename_ = builder.createString(filename);
|
||||
msg.ReadFile.startReadFile(builder);
|
||||
msg.ReadFile.addFilename(builder, filename_);
|
||||
const inner = msg.ReadFile.endReadFile(builder);
|
||||
return [builder, msg.Any.ReadFile, inner];
|
||||
}
|
||||
|
||||
function res(baseRes: null | msg.Base): Uint8Array {
|
||||
assert(baseRes != null);
|
||||
assert(msg.Any.ReadFileRes === baseRes!.innerType());
|
||||
const inner = new msg.ReadFileRes();
|
||||
assert(baseRes!.inner(inner) != null);
|
||||
const dataArray = inner.dataArray();
|
||||
assert(dataArray != null);
|
||||
return new Uint8Array(dataArray!);
|
||||
}
|
||||
import { open, openSync } from "./files";
|
||||
import { readAll, readAllSync } from "./buffer";
|
||||
|
||||
/** Read the entire contents of a file synchronously.
|
||||
*
|
||||
|
@ -32,7 +9,10 @@ function res(baseRes: null | msg.Base): Uint8Array {
|
|||
* console.log(decoder.decode(data));
|
||||
*/
|
||||
export function readFileSync(filename: string): Uint8Array {
|
||||
return res(dispatch.sendSync(...req(filename)));
|
||||
const file = openSync(filename);
|
||||
const contents = readAllSync(file);
|
||||
file.close();
|
||||
return contents;
|
||||
}
|
||||
|
||||
/** Read the entire contents of a file.
|
||||
|
@ -42,5 +22,8 @@ export function readFileSync(filename: string): Uint8Array {
|
|||
* console.log(decoder.decode(data));
|
||||
*/
|
||||
export async function readFile(filename: string): Promise<Uint8Array> {
|
||||
return res(await dispatch.sendAsync(...req(filename)));
|
||||
const file = await open(filename);
|
||||
const contents = await readAll(file);
|
||||
file.close();
|
||||
return contents;
|
||||
}
|
||||
|
|
|
@ -1,35 +1,7 @@
|
|||
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
|
||||
import * as msg from "gen/msg_generated";
|
||||
import * as flatbuffers from "./flatbuffers";
|
||||
import * as dispatch from "./dispatch";
|
||||
|
||||
function req(
|
||||
filename: string,
|
||||
data: Uint8Array,
|
||||
options: WriteFileOptions
|
||||
): [flatbuffers.Builder, msg.Any, flatbuffers.Offset, Uint8Array] {
|
||||
const builder = flatbuffers.createBuilder();
|
||||
const filename_ = builder.createString(filename);
|
||||
msg.WriteFile.startWriteFile(builder);
|
||||
msg.WriteFile.addFilename(builder, filename_);
|
||||
// Perm is not updated by default
|
||||
if (options.perm !== undefined && options.perm !== null) {
|
||||
msg.WriteFile.addUpdatePerm(builder, true);
|
||||
msg.WriteFile.addPerm(builder, options.perm!);
|
||||
} else {
|
||||
msg.WriteFile.addUpdatePerm(builder, false);
|
||||
msg.WriteFile.addPerm(builder, 0o666);
|
||||
}
|
||||
// Create is turned on by default
|
||||
if (options.create !== undefined) {
|
||||
msg.WriteFile.addIsCreate(builder, !!options.create);
|
||||
} else {
|
||||
msg.WriteFile.addIsCreate(builder, true);
|
||||
}
|
||||
msg.WriteFile.addIsAppend(builder, !!options.append);
|
||||
const inner = msg.WriteFile.endWriteFile(builder);
|
||||
return [builder, msg.Any.WriteFile, inner, data];
|
||||
}
|
||||
import { stat, statSync } from "./stat";
|
||||
import { open, openSync } from "./files";
|
||||
import { chmod, chmodSync } from "./chmod";
|
||||
|
||||
/** Options for writing to a file.
|
||||
* `perm` would change the file's permission if set.
|
||||
|
@ -53,7 +25,23 @@ export function writeFileSync(
|
|||
data: Uint8Array,
|
||||
options: WriteFileOptions = {}
|
||||
): void {
|
||||
dispatch.sendSync(...req(filename, data, options));
|
||||
if (options.create !== undefined) {
|
||||
const create = !!options.create;
|
||||
if (!create) {
|
||||
// verify that file exists
|
||||
statSync(filename);
|
||||
}
|
||||
}
|
||||
|
||||
const openMode = !!options.append ? "a" : "w";
|
||||
const file = openSync(filename, openMode);
|
||||
|
||||
if (options.perm !== undefined && options.perm !== null) {
|
||||
chmodSync(filename, options.perm);
|
||||
}
|
||||
|
||||
file.writeSync(data);
|
||||
file.close();
|
||||
}
|
||||
|
||||
/** Write a new file, with given filename and data.
|
||||
|
@ -67,5 +55,21 @@ export async function writeFile(
|
|||
data: Uint8Array,
|
||||
options: WriteFileOptions = {}
|
||||
): Promise<void> {
|
||||
await dispatch.sendAsync(...req(filename, data, options));
|
||||
if (options.create !== undefined) {
|
||||
const create = !!options.create;
|
||||
if (!create) {
|
||||
// verify that file exists
|
||||
await stat(filename);
|
||||
}
|
||||
}
|
||||
|
||||
const openMode = !!options.append ? "a" : "w";
|
||||
const file = await open(filename, openMode);
|
||||
|
||||
if (options.perm !== undefined && options.perm !== null) {
|
||||
await chmod(filename, options.perm);
|
||||
}
|
||||
|
||||
await file.write(data);
|
||||
file.close();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue