forked from denoland/deno
-
Notifications
You must be signed in to change notification settings - Fork 0
/
io.ts
175 lines (155 loc) · 6.08 KB
/
io.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
// Copyright 2018-2019 the Deno authors. All rights reserved. MIT license.
// Interfaces 100% copied from Go.
// Documentation liberally lifted from them too.
// Thank you! We love Go!
// The bytes read during an I/O call and a boolean indicating EOF.
export interface ReadResult {
nread: number;
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 {
/** Reads up to p.byteLength bytes into `p`. It resolves to the number
* of bytes read (`0` <= `n` <= `p.byteLength`) and any error encountered.
* Even if `read()` returns `n` < `p.byteLength`, it may use all of `p` as
* scratch space during the call. If some data is available but not
* `p.byteLength` bytes, `read()` conventionally returns what is available
* instead of waiting for more.
*
* When `read()` encounters an error or end-of-file condition after
* successfully reading `n` > `0` bytes, it returns the number of bytes read.
* It may return the (non-nil) error from the same call or return the error
* (and `n` == `0`) from a subsequent call. An instance of this general case
* is that a `Reader` returning a non-zero number of bytes at the end of the
* input stream may return either `err` == `EOF` or `err` == `null`. The next
* `read()` should return `0`, `EOF`.
*
* Callers should always process the `n` > `0` bytes returned before
* considering the `EOF`. Doing so correctly handles I/O errors that happen
* after reading some bytes and also both of the allowed `EOF` behaviors.
*
* Implementations of `read()` are discouraged from returning a zero byte
* count with a `null` error, except when `p.byteLength` == `0`. Callers
* should treat a return of `0` and `null` as indicating that nothing
* happened; in particular it does not indicate `EOF`.
*
* Implementations must not retain `p`.
*/
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 {
/** Writes `p.byteLength` bytes from `p` to the underlying data
* stream. It resolves to the number of bytes written from `p` (`0` <= `n` <=
* `p.byteLength`) and any error encountered that caused the write to stop
* early. `write()` must return a non-null error if it returns `n` <
* `p.byteLength`. write() must not modify the slice data, even temporarily.
*
* Implementations must not retain `p`.
*/
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
// implementations may document their own behavior.
close(): void;
}
// https://golang.org/pkg/io/#Seeker
export interface Seeker {
/** Seek sets the offset for the next `read()` or `write()` to offset,
* interpreted according to `whence`: `SeekStart` means relative to the start
* of the file, `SeekCurrent` means relative to the current offset, and
* `SeekEnd` means relative to the end. Seek returns the new offset relative
* to the start of the file and an error, if any.
*
* Seeking to an offset before the start of the file is an error. Seeking to
* any positive offset is legal, but the behavior of subsequent I/O operations
* on the underlying object is implementation-dependent.
*/
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 {}
// https://golang.org/pkg/io/#WriteCloser
export interface WriteCloser extends Writer, Closer {}
// https://golang.org/pkg/io/#ReadSeeker
export interface ReadSeeker extends Reader, Seeker {}
// https://golang.org/pkg/io/#WriteSeeker
export interface WriteSeeker extends Writer, Seeker {}
// https://golang.org/pkg/io/#ReadWriteCloser
export interface ReadWriteCloser extends Reader, Writer, Closer {}
// https://golang.org/pkg/io/#ReadWriteSeeker
export interface ReadWriteSeeker extends Reader, Writer, Seeker {}
/** Copies from `src` to `dst` until either `EOF` is reached on `src`
* or an error occurs. It returns the number of bytes copied and the first
* error encountered while copying, if any.
*
* Because `copy()` is defined to read from `src` until `EOF`, it does not
* treat an `EOF` from `read()` as an error to be reported.
*/
// https://golang.org/pkg/io/#Copy
export async function copy(dst: Writer, src: Reader): Promise<number> {
let n = 0;
const b = new Uint8Array(32 * 1024);
let gotEOF = false;
while (gotEOF === false) {
const result = await src.read(b);
if (result.eof) {
gotEOF = true;
}
n += await dst.write(b.subarray(0, result.nread));
}
return n;
}
/** Turns `r` into async iterator.
*
* for await (const chunk of toAsyncIterator(reader)) {
* console.log(chunk)
* }
*/
export function toAsyncIterator(r: Reader): AsyncIterableIterator<Uint8Array> {
const b = new Uint8Array(1024);
// Keep track if end-of-file has been reached, then
// signal that iterator is done during subsequent next()
// call. This is required because `r` can return a `ReadResult`
// with data read and EOF reached. But if iterator returns
// `done` then `value` is discarded.
//
// See https://github.com/denoland/deno/issues/2330 for reference.
let sawEof = false;
return {
[Symbol.asyncIterator](): AsyncIterableIterator<Uint8Array> {
return this;
},
async next(): Promise<IteratorResult<Uint8Array>> {
if (sawEof) {
return { value: new Uint8Array(), done: true };
}
const result = await r.read(b);
sawEof = result.eof;
return {
value: b.subarray(0, result.nread),
done: false
};
}
};
}