summaryrefslogtreecommitdiff
path: root/io
diff options
context:
space:
mode:
authorYusuke Sakurai <kerokerokerop@gmail.com>2019-02-11 08:49:48 +0900
committerRyan Dahl <ry@tinyclouds.org>2019-02-10 18:49:48 -0500
commit33f62789cde407059abba0a7ac18b2145c648ea7 (patch)
tree454d487f232a61f6c57e2ebdad66e49bf939e4d6 /io
parented20bda6ec324b8143c6210024647d2692232c26 (diff)
feat: multipart, etc.. (denoland/deno_std#180)
Original: https://github.com/denoland/deno_std/commit/fda9c98d055091fa886fa444ebd1adcd2ecd21bc
Diffstat (limited to 'io')
-rw-r--r--io/bufio_test.ts2
-rw-r--r--io/ioutil.ts36
-rw-r--r--io/ioutil_test.ts29
-rw-r--r--io/readers.ts38
-rw-r--r--io/readers_test.ts36
-rw-r--r--io/util.ts26
-rw-r--r--io/util_test.ts15
-rw-r--r--io/writers.ts38
-rw-r--r--io/writers_test.ts14
9 files changed, 220 insertions, 14 deletions
diff --git a/io/bufio_test.ts b/io/bufio_test.ts
index fa8f4b73b..e63f1c5c9 100644
--- a/io/bufio_test.ts
+++ b/io/bufio_test.ts
@@ -30,7 +30,7 @@ test(async function bufioReaderSimple() {
const data = "hello world";
const b = new BufReader(stringsReader(data));
const s = await readBytes(b);
- assertEqual(s, data);
+ assert.equal(s, data);
});
type ReadMaker = { name: string; fn: (r: Reader) => Reader };
diff --git a/io/ioutil.ts b/io/ioutil.ts
index 68d6e5190..6590c0f66 100644
--- a/io/ioutil.ts
+++ b/io/ioutil.ts
@@ -1,27 +1,55 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { BufReader } from "./bufio.ts";
+import { Reader, Writer } from "deno";
+import { assert } from "../testing/mod.ts";
-/* Read big endian 16bit short from BufReader */
+/** copy N size at the most. If read size is lesser than N, then returns nread */
+export async function copyN(
+ dest: Writer,
+ r: Reader,
+ size: number
+): Promise<number> {
+ let bytesRead = 0;
+ let buf = new Uint8Array(1024);
+ while (bytesRead < size) {
+ if (size - bytesRead < 1024) {
+ buf = new Uint8Array(size - bytesRead);
+ }
+ const { nread, eof } = await r.read(buf);
+ bytesRead += nread;
+ if (nread > 0) {
+ const n = await dest.write(buf.slice(0, nread));
+ assert.assert(n === nread, "could not write");
+ }
+ if (eof) {
+ break;
+ }
+ }
+ return bytesRead;
+}
+
+/** Read big endian 16bit short from BufReader */
export async function readShort(buf: BufReader): Promise<number> {
const [high, low] = [await buf.readByte(), await buf.readByte()];
return (high << 8) | low;
}
-/* Read big endian 32bit integer from BufReader */
+/** Read big endian 32bit integer from BufReader */
export async function readInt(buf: BufReader): Promise<number> {
const [high, low] = [await readShort(buf), await readShort(buf)];
return (high << 16) | low;
}
const BIT32 = 0xffffffff;
-/* Read big endian 64bit long from BufReader */
+
+/** Read big endian 64bit long from BufReader */
export async function readLong(buf: BufReader): Promise<number> {
const [high, low] = [await readInt(buf), await readInt(buf)];
// ECMAScript doesn't support 64bit bit ops.
return high ? high * (BIT32 + 1) + low : low;
}
-/* Slice number into 64bit big endian byte array */
+/** Slice number into 64bit big endian byte array */
export function sliceLongToBytes(d: number, dest = new Array(8)): number[] {
let mask = 0xff;
let low = (d << 32) >>> 32;
diff --git a/io/ioutil_test.ts b/io/ioutil_test.ts
index 4ff69352a..2c78b2562 100644
--- a/io/ioutil_test.ts
+++ b/io/ioutil_test.ts
@@ -1,8 +1,15 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
-import { Reader, ReadResult } from "deno";
-import { assertEqual, test } from "../testing/mod.ts";
-import { readInt, readLong, readShort, sliceLongToBytes } from "./ioutil.ts";
+import { Buffer, Reader, ReadResult } from "deno";
+import { assert, assertEqual, runTests, test } from "../testing/mod.ts";
+import {
+ copyN,
+ readInt,
+ readLong,
+ readShort,
+ sliceLongToBytes
+} from "./ioutil.ts";
import { BufReader } from "./bufio.ts";
+import { stringsReader } from "./util.ts";
class BinaryReader implements Reader {
index = 0;
@@ -61,3 +68,19 @@ test(async function testSliceLongToBytes2() {
const arr = sliceLongToBytes(0x12345678);
assertEqual(arr, [0, 0, 0, 0, 0x12, 0x34, 0x56, 0x78]);
});
+
+test(async function testCopyN1() {
+ const w = new Buffer();
+ const r = stringsReader("abcdefghij");
+ const n = await copyN(w, r, 3);
+ assert.equal(n, 3);
+ assert.equal(w.toString(), "abc");
+});
+
+test(async function testCopyN2() {
+ const w = new Buffer();
+ const r = stringsReader("abcdefghij");
+ const n = await copyN(w, r, 11);
+ assert.equal(n, 10);
+ assert.equal(w.toString(), "abcdefghij");
+});
diff --git a/io/readers.ts b/io/readers.ts
new file mode 100644
index 000000000..df0299356
--- /dev/null
+++ b/io/readers.ts
@@ -0,0 +1,38 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+import { Reader, ReadResult } from "deno";
+import { encode } from "../strings/strings.ts";
+
+/** Reader utility for strings */
+export class StringReader implements Reader {
+ private offs = 0;
+ private buf = new Uint8Array(encode(this.s));
+
+ constructor(private readonly s: string) {}
+
+ async read(p: Uint8Array): Promise<ReadResult> {
+ const n = Math.min(p.byteLength, this.buf.byteLength - this.offs);
+ p.set(this.buf.slice(this.offs, this.offs + n));
+ this.offs += n;
+ return { nread: n, eof: this.offs === this.buf.byteLength };
+ }
+}
+
+/** Reader utility for combining multiple readers */
+export class MultiReader implements Reader {
+ private readonly readers: Reader[];
+ private currentIndex = 0;
+
+ constructor(...readers: Reader[]) {
+ this.readers = readers;
+ }
+
+ async read(p: Uint8Array): Promise<ReadResult> {
+ const r = this.readers[this.currentIndex];
+ if (!r) return { nread: 0, eof: true };
+ const { nread, eof } = await r.read(p);
+ if (eof) {
+ this.currentIndex++;
+ }
+ return { nread, eof: false };
+ }
+}
diff --git a/io/readers_test.ts b/io/readers_test.ts
new file mode 100644
index 000000000..0bc8ca36a
--- /dev/null
+++ b/io/readers_test.ts
@@ -0,0 +1,36 @@
+import { assert, test } from "../testing/mod.ts";
+import { MultiReader, StringReader } from "./readers.ts";
+import { StringWriter } from "./writers.ts";
+import { copy } from "deno";
+import { copyN } from "./ioutil.ts";
+import { decode } from "../strings/strings.ts";
+
+test(async function ioStringReader() {
+ const r = new StringReader("abcdef");
+ const { nread, eof } = await r.read(new Uint8Array(6));
+ assert.equal(nread, 6);
+ assert.equal(eof, true);
+});
+
+test(async function ioStringReader() {
+ const r = new StringReader("abcdef");
+ const buf = new Uint8Array(3);
+ let res1 = await r.read(buf);
+ assert.equal(res1.nread, 3);
+ assert.equal(res1.eof, false);
+ assert.equal(decode(buf), "abc");
+ let res2 = await r.read(buf);
+ assert.equal(res2.nread, 3);
+ assert.equal(res2.eof, true);
+ assert.equal(decode(buf), "def");
+});
+
+test(async function ioMultiReader() {
+ const r = new MultiReader(new StringReader("abc"), new StringReader("def"));
+ const w = new StringWriter();
+ const n = await copyN(w, r, 4);
+ assert.equal(n, 4);
+ assert.equal(w.toString(), "abcd");
+ await copy(w, r);
+ assert.equal(w.toString(), "abcdef");
+});
diff --git a/io/util.ts b/io/util.ts
index 8726a1887..954808c6c 100644
--- a/io/util.ts
+++ b/io/util.ts
@@ -1,6 +1,7 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
-import { Buffer, Reader } from "deno";
-
+import { Buffer, File, mkdir, open, Reader } from "deno";
+import { encode } from "../strings/strings.ts";
+import * as path from "../fs/path.ts";
// `off` is the offset into `dst` where it will at which to begin writing values
// from `src`.
// Returns the number of bytes copied.
@@ -18,8 +19,23 @@ export function charCode(s: string): number {
return s.charCodeAt(0);
}
-const encoder = new TextEncoder();
export function stringsReader(s: string): Reader {
- const ui8 = encoder.encode(s);
- return new Buffer(ui8.buffer as ArrayBuffer);
+ return new Buffer(encode(s).buffer);
+}
+
+/** Create or open a temporal file at specified directory with prefix and postfix */
+export async function tempFile(
+ dir: string,
+ opts: {
+ prefix?: string;
+ postfix?: string;
+ } = { prefix: "", postfix: "" }
+): Promise<{ file: File; filepath: string }> {
+ const r = Math.floor(Math.random() * 1000000);
+ const filepath = path.resolve(
+ `${dir}/${opts.prefix || ""}${r}${opts.postfix || ""}`
+ );
+ await mkdir(path.dirname(filepath), true);
+ const file = await open(filepath, "a");
+ return { file, filepath };
}
diff --git a/io/util_test.ts b/io/util_test.ts
index 90ae5d4c1..c3f134616 100644
--- a/io/util_test.ts
+++ b/io/util_test.ts
@@ -1,6 +1,8 @@
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
import { test, assert } from "../testing/mod.ts";
-import { copyBytes } from "./util.ts";
+import { copyBytes, tempFile } from "./util.ts";
+import { remove } from "deno";
+import * as path from "../fs/path.ts";
test(function testCopyBytes() {
let dst = new Uint8Array(4);
@@ -35,3 +37,14 @@ test(function testCopyBytes() {
assert(len === 2);
assert.equal(dst, Uint8Array.of(3, 4, 0, 0));
});
+
+test(async function ioTempfile() {
+ const f = await tempFile(".", {
+ prefix: "prefix-",
+ postfix: "-postfix"
+ });
+ console.log(f.file, f.filepath);
+ const base = path.basename(f.filepath);
+ assert.assert(!!base.match(/^prefix-.+?-postfix$/));
+ await remove(f.filepath);
+});
diff --git a/io/writers.ts b/io/writers.ts
new file mode 100644
index 000000000..15c2628ac
--- /dev/null
+++ b/io/writers.ts
@@ -0,0 +1,38 @@
+// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
+import { Writer } from "deno";
+import { decode, encode } from "../strings/strings.ts";
+
+/** Writer utility for buffering string chunks */
+export class StringWriter implements Writer {
+ private chunks: Uint8Array[] = [];
+ private byteLength: number = 0;
+
+ constructor(private base: string = "") {
+ const c = encode(base);
+ this.chunks.push(c);
+ this.byteLength += c.byteLength;
+ }
+
+ async write(p: Uint8Array): Promise<number> {
+ this.chunks.push(p);
+ this.byteLength += p.byteLength;
+ this.cache = null;
+ return p.byteLength;
+ }
+
+ private cache: string;
+
+ toString(): string {
+ if (this.cache) {
+ return this.cache;
+ }
+ const buf = new Uint8Array(this.byteLength);
+ let offs = 0;
+ for (const chunk of this.chunks) {
+ buf.set(chunk, offs);
+ offs += chunk.byteLength;
+ }
+ this.cache = decode(buf);
+ return this.cache;
+ }
+}
diff --git a/io/writers_test.ts b/io/writers_test.ts
new file mode 100644
index 000000000..01388497c
--- /dev/null
+++ b/io/writers_test.ts
@@ -0,0 +1,14 @@
+import { assert, test } from "../testing/mod.ts";
+import { StringWriter } from "./writers.ts";
+import { StringReader } from "./readers.ts";
+import { copyN } from "./ioutil.ts";
+import { copy } from "deno";
+
+test(async function ioStringWriter() {
+ const w = new StringWriter("base");
+ const r = new StringReader("0123456789");
+ const n = await copyN(w, r, 4);
+ assert.equal(w.toString(), "base0123");
+ await copy(w, r);
+ assert.equal(w.toString(), "base0123456789");
+});