Skip to content

Commit 205e22e

Browse files
committed
feat: add finishTo() for zero-copy serialization into existing buffers
1 parent 1c01075 commit 205e22e

3 files changed

Lines changed: 55 additions & 4 deletions

File tree

index.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2777,6 +2777,15 @@ export class Writer {
27772777
* @returns Finished buffer
27782778
*/
27792779
public finish(): Uint8Array;
2780+
2781+
/**
2782+
* Finishes the write operation, writing into the provided buffer.
2783+
* @param buf Target buffer
2784+
* @param [offset=0] Offset to start writing at
2785+
* @returns The provided buffer
2786+
* @throws {RangeError} If the buffer is too small
2787+
*/
2788+
public finishTo(buf: Uint8Array, offset?: number): Uint8Array;
27802789
}
27812790

27822791
/** Wire format writer using node buffers. */

src/writer.js

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -446,15 +446,27 @@ Writer.prototype.ldelim = function ldelim() {
446446
* @returns {Uint8Array} Finished buffer
447447
*/
448448
Writer.prototype.finish = function finish() {
449-
var head = this.head.next, // skip noop
450-
buf = this.constructor.alloc(this.len),
451-
pos = 0;
449+
return this.finishTo(this.constructor.alloc(this.len), 0);
450+
};
451+
452+
/**
453+
* Finishes the write operation, writing into the provided buffer.
454+
* @param {Uint8Array} buf Target buffer
455+
* @param {number} [offset=0] Offset to start writing at
456+
* @returns {Uint8Array} The provided buffer
457+
* @throws {RangeError} If the buffer is too small
458+
*/
459+
Writer.prototype.finishTo = function finishTo(buf, offset) {
460+
offset |= 0;
461+
if (buf.length - offset < this.len)
462+
throw new RangeError("buffer too small: need " + this.len + " bytes, have " + (buf.length - offset));
463+
var head = this.head.next,
464+
pos = offset;
452465
while (head) {
453466
head.fn(head.val, buf, pos);
454467
pos += head.len;
455468
head = head.next;
456469
}
457-
// this.head = this.tail = null;
458470
return buf;
459471
};
460472

tests/api_writer-reader.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,36 @@ tape.test("writer & reader", function(test) {
129129
test.end();
130130
});
131131

132+
test.test(test.name + " - finishTo", function(test) {
133+
134+
// throws when buffer is too small
135+
var w1 = Writer.create();
136+
w1.uint32(1).uint32(2).uint32(3);
137+
test.throws(function() {
138+
w1.finishTo(new Uint8Array(1));
139+
}, RangeError, "throws RangeError when buffer too small");
140+
141+
// writes at offset and preserves existing data
142+
var w2 = Writer.create();
143+
w2.uint32(100).string("hello").bool(true);
144+
var expected = w2.finish();
145+
146+
var w3 = Writer.create();
147+
w3.uint32(100).string("hello").bool(true);
148+
var offset = 3;
149+
var buf3 = new Uint8Array(offset + w3.len);
150+
for (var i = 0; i < offset; ++i)
151+
buf3[i] = 99;
152+
w3.finishTo(buf3, offset);
153+
154+
for (var i = 0; i < offset; ++i)
155+
test.equal(buf3[i], 99, "preserves byte at index " + i + " before offset");
156+
for (var i = 0; i < expected.length; ++i)
157+
test.equal(buf3[offset + i], expected[i], "byte at offset+" + i + " matches finish()");
158+
159+
test.end();
160+
});
161+
132162
test.throws(function() {
133163
const root = protobuf.Root.fromJSON({
134164
nested: {

0 commit comments

Comments
 (0)