Skip to content

Commit 657d6f1

Browse files
authored
feat: Add finishInto() for zero-copy serialization into existing buffers (#2196)
1 parent 50a5c1d commit 657d6f1

3 files changed

Lines changed: 50 additions & 4 deletions

File tree

index.d.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2859,6 +2859,16 @@ export class Writer {
28592859
* @returns Finished buffer
28602860
*/
28612861
public finish(): Uint8Array;
2862+
2863+
/**
2864+
* Finishes the write operation, writing into the provided buffer.
2865+
* The caller must ensure that `buf` has enough space starting at `offset`
2866+
* to hold {@link Writer#len} bytes.
2867+
* @param buf Target buffer
2868+
* @param [offset=0] Offset to start writing at
2869+
* @returns The provided buffer
2870+
*/
2871+
public finishInto<T extends Uint8Array>(buf: T, offset?: number): T;
28622872
}
28632873

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

src/writer.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -456,15 +456,28 @@ Writer.prototype.ldelim = function ldelim() {
456456
* @returns {Uint8Array} Finished buffer
457457
*/
458458
Writer.prototype.finish = function finish() {
459-
var head = this.head.next, // skip noop
460-
buf = this.constructor.alloc(this.len),
461-
pos = 0;
459+
return this.finishInto(this.constructor.alloc(this.len), 0);
460+
};
461+
462+
/**
463+
* Finishes the write operation, writing into the provided buffer.
464+
* The caller must ensure that `buf` has enough space starting at `offset`
465+
* to hold {@link Writer#len} bytes.
466+
* @param {T} buf Target buffer
467+
* @param {number} [offset=0] Offset to start writing at
468+
* @returns {T} The provided buffer
469+
* @template T extends Uint8Array
470+
*/
471+
Writer.prototype.finishInto = function finishInto(buf, offset) {
472+
if (offset === undefined)
473+
offset = 0;
474+
var head = this.head.next,
475+
pos = offset;
462476
while (head) {
463477
head.fn(head.val, buf, pos);
464478
pos += head.len;
465479
head = head.next;
466480
}
467-
// this.head = this.tail = null;
468481
return buf;
469482
};
470483

tests/api_writer-reader.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,29 @@ tape.test("writer & reader", function(test) {
145145
test.end();
146146
});
147147

148+
test.test(test.name + " - finishInto", function(test) {
149+
150+
// writes at offset and preserves existing data
151+
var w2 = Writer.create();
152+
w2.uint32(100).string("hello").bool(true);
153+
var expected = w2.finish();
154+
155+
var w3 = Writer.create();
156+
w3.uint32(100).string("hello").bool(true);
157+
var offset = 3;
158+
var buf3 = new Uint8Array(offset + w3.len);
159+
for (var i = 0; i < offset; ++i)
160+
buf3[i] = 99;
161+
w3.finishInto(buf3, offset);
162+
163+
for (var i = 0; i < offset; ++i)
164+
test.equal(buf3[i], 99, "preserves byte at index " + i + " before offset");
165+
for (var i = 0; i < expected.length; ++i)
166+
test.equal(buf3[offset + i], expected[i], "byte at offset+" + i + " matches finish()");
167+
168+
test.end();
169+
});
170+
148171
test.throws(function() {
149172
const root = protobuf.Root.fromJSON({
150173
nested: {

0 commit comments

Comments
 (0)