Skip to content

Commit 575b3a5

Browse files
committed
Fixed #57
1 parent 392a7a9 commit 575b3a5

24 files changed

+973
-300
lines changed

compiled/download.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiled/upload-download.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiled/upload.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/lib/appendable-stream.d.ts

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,13 @@ import AppendableBuffer from './appendable';
55
* A wrapper around a writable stream
66
* to implement [[AppendableBuffer]].
77
* The stream must be explicitly closed
8-
* by calling [[AppendableStream.end]]
9-
* after all bytes have been written.
8+
* by calling [[end]] after all bytes
9+
* have been written.
1010
*/
1111
export default class AppendableStream implements AppendableBuffer {
1212
private readonly outStream;
1313
private writtenBytes;
14+
private paused;
1415
/**
1516
* @param outStream The underlying writable stream
1617
*/
@@ -35,4 +36,30 @@ export default class AppendableStream implements AppendableBuffer {
3536
* The number of bytes that have been written
3637
*/
3738
readonly length: number;
39+
/**
40+
* Pauses the writing process, i.e.
41+
* bytes added are not written
42+
* to the underlying output until
43+
* [[resume]] is next called and
44+
* can be cancelled from being written
45+
* by calling [[reset]].
46+
* @throws If paused earlier and never resumed
47+
*/
48+
pause(): this;
49+
/**
50+
* See [[pause]].
51+
* Flushes all paused data to the output
52+
* and exits paused mode.
53+
* @throws If not currently paused
54+
*/
55+
resume(): this;
56+
/**
57+
* See [[pause]].
58+
* Restores state to immediately after
59+
* this [[AppendableBuffer]] was paused.
60+
* Prevents paused data from ever
61+
* being flushed to the output.
62+
* @throws If not currently paused
63+
*/
64+
reset(): this;
3865
}

dist/lib/appendable-stream.js

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
33
const http_1 = require("http");
44
const stream_1 = require("stream");
55
const assert_1 = require("./assert");
6+
const growable_buffer_1 = require("./growable-buffer");
67
const WRITABLE_STREAMS = [stream_1.Writable, stream_1.Duplex, http_1.OutgoingMessage];
78
/**
89
* A wrapper around a writable stream
910
* to implement [[AppendableBuffer]].
1011
* The stream must be explicitly closed
11-
* by calling [[AppendableStream.end]]
12-
* after all bytes have been written.
12+
* by calling [[end]] after all bytes
13+
* have been written.
1314
*/
1415
class AppendableStream {
1516
/**
@@ -19,6 +20,7 @@ class AppendableStream {
1920
assert_1.default.instanceOf(outStream, WRITABLE_STREAMS);
2021
this.outStream = outStream;
2122
this.writtenBytes = 0;
23+
this.paused = null;
2224
}
2325
/**
2426
* Appends a byte to the end
@@ -28,9 +30,7 @@ class AppendableStream {
2830
add(value) {
2931
assert_1.default.integer(value);
3032
assert_1.default.between(0, value, 0x100, 'Not a byte: ' + String(value));
31-
this.outStream.write(Buffer.from([value]));
32-
this.writtenBytes++;
33-
return this;
33+
return this.addAll(new Uint8Array([value]).buffer);
3434
}
3535
/**
3636
* Appends a contiguous set of bytes
@@ -39,7 +39,10 @@ class AppendableStream {
3939
*/
4040
addAll(buffer) {
4141
assert_1.default.instanceOf(buffer, ArrayBuffer);
42-
this.outStream.write(Buffer.from(buffer));
42+
if (this.paused)
43+
this.paused.addAll(buffer);
44+
else
45+
this.outStream.write(Buffer.from(buffer));
4346
this.writtenBytes += buffer.byteLength;
4447
return this;
4548
}
@@ -55,5 +58,48 @@ class AppendableStream {
5558
get length() {
5659
return this.writtenBytes;
5760
}
61+
/**
62+
* Pauses the writing process, i.e.
63+
* bytes added are not written
64+
* to the underlying output until
65+
* [[resume]] is next called and
66+
* can be cancelled from being written
67+
* by calling [[reset]].
68+
* @throws If paused earlier and never resumed
69+
*/
70+
pause() {
71+
assert_1.default(this.paused === null, 'Already paused');
72+
this.paused = new growable_buffer_1.default;
73+
return this;
74+
}
75+
/**
76+
* See [[pause]].
77+
* Flushes all paused data to the output
78+
* and exits paused mode.
79+
* @throws If not currently paused
80+
*/
81+
resume() {
82+
if (!this.paused)
83+
throw new Error('Was not paused');
84+
const { length } = this.paused;
85+
this.outStream.write(Buffer.from(this.paused.rawBuffer, 0, length));
86+
this.paused = null;
87+
return this;
88+
}
89+
/**
90+
* See [[pause]].
91+
* Restores state to immediately after
92+
* this [[AppendableBuffer]] was paused.
93+
* Prevents paused data from ever
94+
* being flushed to the output.
95+
* @throws If not currently paused
96+
*/
97+
reset() {
98+
if (!this.paused)
99+
throw new Error('Was not paused');
100+
this.writtenBytes -= this.paused.length;
101+
this.paused = new growable_buffer_1.default;
102+
return this;
103+
}
58104
}
59105
exports.default = AppendableStream;

dist/lib/appendable.d.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@
33
* to be able to write type and value bytes.
44
* Implemented by [[GrowableBuffer]], as well as
55
* [[AppendableStream]] (a wrapper around a writable stream).
6+
* All methods can be chained, e.g.
7+
* ````javascript
8+
* let gb = new GrowableBuffer
9+
* gb
10+
* .add(1).add(2)
11+
* .addAll(new Uint8Array([3, 4, 5]).buffer)
12+
* .pause()
13+
* .add(0)
14+
* .reset()
15+
* .resume()
16+
* console.log(new Uint8Array(gb.toBuffer())) //Uint8Array [ 1, 2, 3, 4, 5 ]
17+
* ````
618
*/
719
export default interface AppendableBuffer {
820
/**
@@ -23,4 +35,30 @@ export default interface AppendableBuffer {
2335
* position `this.length + i`.
2436
*/
2537
addAll(buffer: ArrayBuffer): this;
38+
/**
39+
* Pauses the writing process, i.e.
40+
* bytes added are not written
41+
* to the underlying output until
42+
* [[resume]] is next called and
43+
* can be cancelled from being written
44+
* by calling [[reset]].
45+
* @throws If paused earlier and never resumed
46+
*/
47+
pause(): this;
48+
/**
49+
* See [[pause]].
50+
* Flushes all paused data to the output
51+
* and exits paused mode.
52+
* @throws If not currently paused
53+
*/
54+
resume(): this;
55+
/**
56+
* See [[pause]].
57+
* Restores state to immediately after
58+
* this [[AppendableBuffer]] was paused.
59+
* Prevents paused data from ever
60+
* being flushed to the output.
61+
* @throws If not currently paused
62+
*/
63+
reset(): this;
2664
}

dist/lib/growable-buffer.d.ts

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ import AppendableBuffer from './appendable';
99
export default class GrowableBuffer implements AppendableBuffer {
1010
private buffer;
1111
private size;
12+
/**
13+
* The length of the buffer before the current pause,
14+
* or `null` if not currently paused
15+
*/
16+
private commitedSize;
1217
/**
1318
* @param initialLength
1419
* The number of bytes in the internal buffer at start
@@ -33,34 +38,6 @@ export default class GrowableBuffer implements AppendableBuffer {
3338
* in the internal buffer after the method returns
3439
*/
3540
grow(size: number): this;
36-
/**
37-
* Sets a byte's value.
38-
* The byte must lie in the occupied portion
39-
* of the internal buffer.
40-
* @param index The position of the byte (0-indexed)
41-
* @param value The value to set the byte to
42-
* (must fit in an unsigned byte)
43-
*/
44-
set(index: number, value: number): this;
45-
/**
46-
* Sets a set of contiguous bytes' values.
47-
* Each byte must lie in the occupied portion
48-
* of the internal buffer.
49-
* @param index The position of the first byte (0-indexed)
50-
* @param buffer The values to write, starting at `index`
51-
* (the byte at position `i` in `buffer` will be written to
52-
* position `index + i` of the [[GrowableBuffer]])
53-
*/
54-
setAll(index: number, buffer: ArrayBuffer): this;
55-
/**
56-
* Gets a byte's value.
57-
* The byte must lie in the occupied portion
58-
* of the internal buffer.
59-
* @param index The position of the byte (0-indexed)
60-
* @return The unsigned byte at the specified index
61-
* of the internal buffer
62-
*/
63-
get(index: number): number;
6441
/**
6542
* Adds a byte after the end of the
6643
* occupied portion of the internal buffer
@@ -86,4 +63,30 @@ export default class GrowableBuffer implements AppendableBuffer {
8663
* @return The internal buffer trimmed to `this.length`
8764
*/
8865
toBuffer(): ArrayBuffer;
66+
/**
67+
* Pauses the writing process, i.e.
68+
* bytes added are not written
69+
* to the underlying output until
70+
* [[resume]] is next called and
71+
* can be cancelled from being written
72+
* by calling [[reset]].
73+
* @throws If paused earlier and never resumed
74+
*/
75+
pause(): this;
76+
/**
77+
* See [[pause]].
78+
* Flushes all paused data to the output
79+
* and exits paused mode.
80+
* @throws If not currently paused
81+
*/
82+
resume(): this;
83+
/**
84+
* See [[pause]].
85+
* Restores state to immediately after
86+
* this [[AppendableBuffer]] was paused.
87+
* Prevents paused data from ever
88+
* being flushed to the output.
89+
* @throws If not currently paused
90+
*/
91+
reset(): this;
8992
}

dist/lib/growable-buffer.js

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,14 @@ class GrowableBuffer {
1818
constructor(initialLength = INITIAL_LENGTH) {
1919
try {
2020
assert_1.default.integer(initialLength);
21-
assert_1.default.between(0, initialLength, Number.MAX_SAFE_INTEGER + 1);
21+
assert_1.default(initialLength >= 0);
2222
}
2323
catch (e) {
2424
throw new RangeError(String(initialLength) + ' is not a valid buffer length');
2525
}
2626
this.buffer = new ArrayBuffer(initialLength);
2727
this.size = 0;
28+
this.commitedSize = null;
2829
}
2930
/**
3031
* The current number of bytes being occupied.
@@ -54,48 +55,6 @@ class GrowableBuffer {
5455
}
5556
return this;
5657
}
57-
/**
58-
* Sets a byte's value.
59-
* The byte must lie in the occupied portion
60-
* of the internal buffer.
61-
* @param index The position of the byte (0-indexed)
62-
* @param value The value to set the byte to
63-
* (must fit in an unsigned byte)
64-
*/
65-
set(index, value) {
66-
assert_1.default.integer(value);
67-
assert_1.default.between(0, value, 0x100, 'Not a byte: ' + String(value));
68-
return this.setAll(index, new Uint8Array([value]).buffer);
69-
}
70-
/**
71-
* Sets a set of contiguous bytes' values.
72-
* Each byte must lie in the occupied portion
73-
* of the internal buffer.
74-
* @param index The position of the first byte (0-indexed)
75-
* @param buffer The values to write, starting at `index`
76-
* (the byte at position `i` in `buffer` will be written to
77-
* position `index + i` of the [[GrowableBuffer]])
78-
*/
79-
setAll(index, buffer) {
80-
assert_1.default.instanceOf(buffer, ArrayBuffer);
81-
assert_1.default.integer(index);
82-
assert_1.default.between(0, index, this.size - buffer.byteLength + 1, 'Index out of bounds: ' + String(index));
83-
new Uint8Array(this.buffer).set(new Uint8Array(buffer), index);
84-
return this;
85-
}
86-
/**
87-
* Gets a byte's value.
88-
* The byte must lie in the occupied portion
89-
* of the internal buffer.
90-
* @param index The position of the byte (0-indexed)
91-
* @return The unsigned byte at the specified index
92-
* of the internal buffer
93-
*/
94-
get(index) {
95-
assert_1.default.integer(index);
96-
assert_1.default.between(0, index, this.size, 'Index out of bounds: ' + String(index));
97-
return new Uint8Array(this.buffer)[index];
98-
}
9958
/**
10059
* Adds a byte after the end of the
10160
* occupied portion of the internal buffer
@@ -135,7 +94,51 @@ class GrowableBuffer {
13594
* @return The internal buffer trimmed to `this.length`
13695
*/
13796
toBuffer() {
138-
return this.buffer.slice(0, this.size);
97+
let length;
98+
if (this.commitedSize === null)
99+
length = this.size;
100+
else
101+
length = this.commitedSize;
102+
return this.buffer.slice(0, length);
103+
}
104+
/**
105+
* Pauses the writing process, i.e.
106+
* bytes added are not written
107+
* to the underlying output until
108+
* [[resume]] is next called and
109+
* can be cancelled from being written
110+
* by calling [[reset]].
111+
* @throws If paused earlier and never resumed
112+
*/
113+
pause() {
114+
assert_1.default(this.commitedSize === null, 'Already paused');
115+
this.commitedSize = this.size;
116+
return this;
117+
}
118+
/**
119+
* See [[pause]].
120+
* Flushes all paused data to the output
121+
* and exits paused mode.
122+
* @throws If not currently paused
123+
*/
124+
resume() {
125+
assert_1.default(this.commitedSize !== null, 'Was not paused');
126+
this.commitedSize = null;
127+
return this;
128+
}
129+
/**
130+
* See [[pause]].
131+
* Restores state to immediately after
132+
* this [[AppendableBuffer]] was paused.
133+
* Prevents paused data from ever
134+
* being flushed to the output.
135+
* @throws If not currently paused
136+
*/
137+
reset() {
138+
if (this.commitedSize === null)
139+
throw new Error('Was not paused');
140+
this.size = this.commitedSize;
141+
return this;
139142
}
140143
}
141144
exports.default = GrowableBuffer;

0 commit comments

Comments
 (0)