diff options
| author | Yusuke Sakurai <kerokerokerop@gmail.com> | 2019-02-11 08:49:48 +0900 |
|---|---|---|
| committer | Ryan Dahl <ry@tinyclouds.org> | 2019-02-10 18:49:48 -0500 |
| commit | 33f62789cde407059abba0a7ac18b2145c648ea7 (patch) | |
| tree | 454d487f232a61f6c57e2ebdad66e49bf939e4d6 /io | |
| parent | ed20bda6ec324b8143c6210024647d2692232c26 (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.ts | 2 | ||||
| -rw-r--r-- | io/ioutil.ts | 36 | ||||
| -rw-r--r-- | io/ioutil_test.ts | 29 | ||||
| -rw-r--r-- | io/readers.ts | 38 | ||||
| -rw-r--r-- | io/readers_test.ts | 36 | ||||
| -rw-r--r-- | io/util.ts | 26 | ||||
| -rw-r--r-- | io/util_test.ts | 15 | ||||
| -rw-r--r-- | io/writers.ts | 38 | ||||
| -rw-r--r-- | io/writers_test.ts | 14 |
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"); +}); |
