Skip to content

Commit

Permalink
Fixed #57
Browse files Browse the repository at this point in the history
  • Loading branch information
calebsander committed Sep 25, 2017
1 parent 392a7a9 commit 575b3a5
Show file tree
Hide file tree
Showing 24 changed files with 973 additions and 300 deletions.
4 changes: 2 additions & 2 deletions compiled/download.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions compiled/upload-download.js

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions compiled/upload.js

Large diffs are not rendered by default.

31 changes: 29 additions & 2 deletions dist/lib/appendable-stream.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import AppendableBuffer from './appendable';
* A wrapper around a writable stream
* to implement [[AppendableBuffer]].
* The stream must be explicitly closed
* by calling [[AppendableStream.end]]
* after all bytes have been written.
* by calling [[end]] after all bytes
* have been written.
*/
export default class AppendableStream implements AppendableBuffer {
private readonly outStream;
private writtenBytes;
private paused;
/**
* @param outStream The underlying writable stream
*/
Expand All @@ -35,4 +36,30 @@ export default class AppendableStream implements AppendableBuffer {
* The number of bytes that have been written
*/
readonly length: number;
/**
* Pauses the writing process, i.e.
* bytes added are not written
* to the underlying output until
* [[resume]] is next called and
* can be cancelled from being written
* by calling [[reset]].
* @throws If paused earlier and never resumed
*/
pause(): this;
/**
* See [[pause]].
* Flushes all paused data to the output
* and exits paused mode.
* @throws If not currently paused
*/
resume(): this;
/**
* See [[pause]].
* Restores state to immediately after
* this [[AppendableBuffer]] was paused.
* Prevents paused data from ever
* being flushed to the output.
* @throws If not currently paused
*/
reset(): this;
}
58 changes: 52 additions & 6 deletions dist/lib/appendable-stream.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
const http_1 = require("http");
const stream_1 = require("stream");
const assert_1 = require("./assert");
const growable_buffer_1 = require("./growable-buffer");
const WRITABLE_STREAMS = [stream_1.Writable, stream_1.Duplex, http_1.OutgoingMessage];
/**
* A wrapper around a writable stream
* to implement [[AppendableBuffer]].
* The stream must be explicitly closed
* by calling [[AppendableStream.end]]
* after all bytes have been written.
* by calling [[end]] after all bytes
* have been written.
*/
class AppendableStream {
/**
Expand All @@ -19,6 +20,7 @@ class AppendableStream {
assert_1.default.instanceOf(outStream, WRITABLE_STREAMS);
this.outStream = outStream;
this.writtenBytes = 0;
this.paused = null;
}
/**
* Appends a byte to the end
Expand All @@ -28,9 +30,7 @@ class AppendableStream {
add(value) {
assert_1.default.integer(value);
assert_1.default.between(0, value, 0x100, 'Not a byte: ' + String(value));
this.outStream.write(Buffer.from([value]));
this.writtenBytes++;
return this;
return this.addAll(new Uint8Array([value]).buffer);
}
/**
* Appends a contiguous set of bytes
Expand All @@ -39,7 +39,10 @@ class AppendableStream {
*/
addAll(buffer) {
assert_1.default.instanceOf(buffer, ArrayBuffer);
this.outStream.write(Buffer.from(buffer));
if (this.paused)
this.paused.addAll(buffer);
else
this.outStream.write(Buffer.from(buffer));
this.writtenBytes += buffer.byteLength;
return this;
}
Expand All @@ -55,5 +58,48 @@ class AppendableStream {
get length() {
return this.writtenBytes;
}
/**
* Pauses the writing process, i.e.
* bytes added are not written
* to the underlying output until
* [[resume]] is next called and
* can be cancelled from being written
* by calling [[reset]].
* @throws If paused earlier and never resumed
*/
pause() {
assert_1.default(this.paused === null, 'Already paused');
this.paused = new growable_buffer_1.default;
return this;
}
/**
* See [[pause]].
* Flushes all paused data to the output
* and exits paused mode.
* @throws If not currently paused
*/
resume() {
if (!this.paused)
throw new Error('Was not paused');
const { length } = this.paused;
this.outStream.write(Buffer.from(this.paused.rawBuffer, 0, length));
this.paused = null;
return this;
}
/**
* See [[pause]].
* Restores state to immediately after
* this [[AppendableBuffer]] was paused.
* Prevents paused data from ever
* being flushed to the output.
* @throws If not currently paused
*/
reset() {
if (!this.paused)
throw new Error('Was not paused');
this.writtenBytes -= this.paused.length;
this.paused = new growable_buffer_1.default;
return this;
}
}
exports.default = AppendableStream;
38 changes: 38 additions & 0 deletions dist/lib/appendable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,18 @@
* to be able to write type and value bytes.
* Implemented by [[GrowableBuffer]], as well as
* [[AppendableStream]] (a wrapper around a writable stream).
* All methods can be chained, e.g.
* ````javascript
* let gb = new GrowableBuffer
* gb
* .add(1).add(2)
* .addAll(new Uint8Array([3, 4, 5]).buffer)
* .pause()
* .add(0)
* .reset()
* .resume()
* console.log(new Uint8Array(gb.toBuffer())) //Uint8Array [ 1, 2, 3, 4, 5 ]
* ````
*/
export default interface AppendableBuffer {
/**
Expand All @@ -23,4 +35,30 @@ export default interface AppendableBuffer {
* position `this.length + i`.
*/
addAll(buffer: ArrayBuffer): this;
/**
* Pauses the writing process, i.e.
* bytes added are not written
* to the underlying output until
* [[resume]] is next called and
* can be cancelled from being written
* by calling [[reset]].
* @throws If paused earlier and never resumed
*/
pause(): this;
/**
* See [[pause]].
* Flushes all paused data to the output
* and exits paused mode.
* @throws If not currently paused
*/
resume(): this;
/**
* See [[pause]].
* Restores state to immediately after
* this [[AppendableBuffer]] was paused.
* Prevents paused data from ever
* being flushed to the output.
* @throws If not currently paused
*/
reset(): this;
}
59 changes: 31 additions & 28 deletions dist/lib/growable-buffer.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import AppendableBuffer from './appendable';
export default class GrowableBuffer implements AppendableBuffer {
private buffer;
private size;
/**
* The length of the buffer before the current pause,
* or `null` if not currently paused
*/
private commitedSize;
/**
* @param initialLength
* The number of bytes in the internal buffer at start
Expand All @@ -33,34 +38,6 @@ export default class GrowableBuffer implements AppendableBuffer {
* in the internal buffer after the method returns
*/
grow(size: number): this;
/**
* Sets a byte's value.
* The byte must lie in the occupied portion
* of the internal buffer.
* @param index The position of the byte (0-indexed)
* @param value The value to set the byte to
* (must fit in an unsigned byte)
*/
set(index: number, value: number): this;
/**
* Sets a set of contiguous bytes' values.
* Each byte must lie in the occupied portion
* of the internal buffer.
* @param index The position of the first byte (0-indexed)
* @param buffer The values to write, starting at `index`
* (the byte at position `i` in `buffer` will be written to
* position `index + i` of the [[GrowableBuffer]])
*/
setAll(index: number, buffer: ArrayBuffer): this;
/**
* Gets a byte's value.
* The byte must lie in the occupied portion
* of the internal buffer.
* @param index The position of the byte (0-indexed)
* @return The unsigned byte at the specified index
* of the internal buffer
*/
get(index: number): number;
/**
* Adds a byte after the end of the
* occupied portion of the internal buffer
Expand All @@ -86,4 +63,30 @@ export default class GrowableBuffer implements AppendableBuffer {
* @return The internal buffer trimmed to `this.length`
*/
toBuffer(): ArrayBuffer;
/**
* Pauses the writing process, i.e.
* bytes added are not written
* to the underlying output until
* [[resume]] is next called and
* can be cancelled from being written
* by calling [[reset]].
* @throws If paused earlier and never resumed
*/
pause(): this;
/**
* See [[pause]].
* Flushes all paused data to the output
* and exits paused mode.
* @throws If not currently paused
*/
resume(): this;
/**
* See [[pause]].
* Restores state to immediately after
* this [[AppendableBuffer]] was paused.
* Prevents paused data from ever
* being flushed to the output.
* @throws If not currently paused
*/
reset(): this;
}
91 changes: 47 additions & 44 deletions dist/lib/growable-buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ class GrowableBuffer {
constructor(initialLength = INITIAL_LENGTH) {
try {
assert_1.default.integer(initialLength);
assert_1.default.between(0, initialLength, Number.MAX_SAFE_INTEGER + 1);
assert_1.default(initialLength >= 0);
}
catch (e) {
throw new RangeError(String(initialLength) + ' is not a valid buffer length');
}
this.buffer = new ArrayBuffer(initialLength);
this.size = 0;
this.commitedSize = null;
}
/**
* The current number of bytes being occupied.
Expand Down Expand Up @@ -54,48 +55,6 @@ class GrowableBuffer {
}
return this;
}
/**
* Sets a byte's value.
* The byte must lie in the occupied portion
* of the internal buffer.
* @param index The position of the byte (0-indexed)
* @param value The value to set the byte to
* (must fit in an unsigned byte)
*/
set(index, value) {
assert_1.default.integer(value);
assert_1.default.between(0, value, 0x100, 'Not a byte: ' + String(value));
return this.setAll(index, new Uint8Array([value]).buffer);
}
/**
* Sets a set of contiguous bytes' values.
* Each byte must lie in the occupied portion
* of the internal buffer.
* @param index The position of the first byte (0-indexed)
* @param buffer The values to write, starting at `index`
* (the byte at position `i` in `buffer` will be written to
* position `index + i` of the [[GrowableBuffer]])
*/
setAll(index, buffer) {
assert_1.default.instanceOf(buffer, ArrayBuffer);
assert_1.default.integer(index);
assert_1.default.between(0, index, this.size - buffer.byteLength + 1, 'Index out of bounds: ' + String(index));
new Uint8Array(this.buffer).set(new Uint8Array(buffer), index);
return this;
}
/**
* Gets a byte's value.
* The byte must lie in the occupied portion
* of the internal buffer.
* @param index The position of the byte (0-indexed)
* @return The unsigned byte at the specified index
* of the internal buffer
*/
get(index) {
assert_1.default.integer(index);
assert_1.default.between(0, index, this.size, 'Index out of bounds: ' + String(index));
return new Uint8Array(this.buffer)[index];
}
/**
* Adds a byte after the end of the
* occupied portion of the internal buffer
Expand Down Expand Up @@ -135,7 +94,51 @@ class GrowableBuffer {
* @return The internal buffer trimmed to `this.length`
*/
toBuffer() {
return this.buffer.slice(0, this.size);
let length;
if (this.commitedSize === null)
length = this.size;
else
length = this.commitedSize;
return this.buffer.slice(0, length);
}
/**
* Pauses the writing process, i.e.
* bytes added are not written
* to the underlying output until
* [[resume]] is next called and
* can be cancelled from being written
* by calling [[reset]].
* @throws If paused earlier and never resumed
*/
pause() {
assert_1.default(this.commitedSize === null, 'Already paused');
this.commitedSize = this.size;
return this;
}
/**
* See [[pause]].
* Flushes all paused data to the output
* and exits paused mode.
* @throws If not currently paused
*/
resume() {
assert_1.default(this.commitedSize !== null, 'Was not paused');
this.commitedSize = null;
return this;
}
/**
* See [[pause]].
* Restores state to immediately after
* this [[AppendableBuffer]] was paused.
* Prevents paused data from ever
* being flushed to the output.
* @throws If not currently paused
*/
reset() {
if (this.commitedSize === null)
throw new Error('Was not paused');
this.size = this.commitedSize;
return this;
}
}
exports.default = GrowableBuffer;
Loading

0 comments on commit 575b3a5

Please sign in to comment.