Skip to content

Commit

Permalink
Add support for buffer configuration. (protobufjs#1257)
Browse files Browse the repository at this point in the history
* Added support for buffer configuration.

* Fixed tests for node 4.

* Fixed deprecated Buffer methods.
  • Loading branch information
tinchoz49 authored and Taylor McIntyre committed Oct 16, 2020
1 parent 1310c7d commit 906ef5a
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 50 deletions.
4 changes: 2 additions & 2 deletions src/index-minimal.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,10 @@ protobuf.configure = configure;
* @returns {undefined}
*/
function configure() {
protobuf.Reader._configure(protobuf.BufferReader);
protobuf.util._configure();
protobuf.Writer._configure(protobuf.BufferWriter);
protobuf.Reader._configure(protobuf.BufferReader);
}

// Set up buffer utility according to the environment
protobuf.Writer._configure(protobuf.BufferWriter);
configure();
28 changes: 17 additions & 11 deletions src/reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,24 +53,28 @@ var create_array = typeof Uint8Array !== "undefined"
throw Error("illegal buffer");
};

var create = function create() {
return util.Buffer
? function create_buffer_setup(buffer) {
return (Reader.create = function create_buffer(buffer) {
return util.Buffer.isBuffer(buffer)
? new BufferReader(buffer)
/* istanbul ignore next */
: create_array(buffer);
})(buffer);
}
/* istanbul ignore next */
: create_array;
};

/**
* Creates a new reader using the specified buffer.
* @function
* @param {Uint8Array|Buffer} buffer Buffer to read from
* @returns {Reader|BufferReader} A {@link BufferReader} if `buffer` is a Buffer, otherwise a {@link Reader}
* @throws {Error} If `buffer` is not a valid buffer
*/
Reader.create = util.Buffer
? function create_buffer_setup(buffer) {
return (Reader.create = function create_buffer(buffer) {
return util.Buffer.isBuffer(buffer)
? new BufferReader(buffer)
/* istanbul ignore next */
: create_array(buffer);
})(buffer);
}
/* istanbul ignore next */
: create_array;
Reader.create = create();

Reader.prototype._slice = util.Array.prototype.subarray || /* istanbul ignore next */ util.Array.prototype.slice;

Expand Down Expand Up @@ -377,6 +381,8 @@ Reader.prototype.skipType = function(wireType) {

Reader._configure = function(BufferReader_) {
BufferReader = BufferReader_;
Reader.create = create();
BufferReader._configure();

var fn = util.Long ? "toLong" : /* istanbul ignore next */ "toNumber";
util.merge(Reader.prototype, {
Expand Down
15 changes: 11 additions & 4 deletions src/reader_buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,21 @@ function BufferReader(buffer) {
*/
}

/* istanbul ignore else */
if (util.Buffer)
BufferReader.prototype._slice = util.Buffer.prototype.slice;
BufferReader._configure = function () {
/* istanbul ignore else */
if (util.Buffer)
BufferReader.prototype._slice = util.Buffer.prototype.slice;
};


/**
* @override
*/
BufferReader.prototype.string = function read_string_buffer() {
var len = this.uint32(); // modifies pos
return this.buf.utf8Slice(this.pos, this.pos = Math.min(this.pos + len, this.len));
return this.buf.utf8Slice
? this.buf.utf8Slice(this.pos, this.pos = Math.min(this.pos + len, this.len))
: this.buf.toString('utf-8', this.pos, this.pos = Math.min(this.pos + len, this.len))
};

/**
Expand All @@ -42,3 +47,5 @@ BufferReader.prototype.string = function read_string_buffer() {
* @function
* @returns {Buffer} Value read
*/

BufferReader._configure();
26 changes: 16 additions & 10 deletions src/writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,21 +121,25 @@ function Writer() {
// part is just a linked list walk calling operations with already prepared values.
}

var create = function create() {
return util.Buffer
? function create_buffer_setup() {
return (Writer.create = function create_buffer() {
return new BufferWriter();
})();
}
/* istanbul ignore next */
: function create_array() {
return new Writer();
};
};

/**
* Creates a new writer.
* @function
* @returns {BufferWriter|Writer} A {@link BufferWriter} when Buffers are supported, otherwise a {@link Writer}
*/
Writer.create = util.Buffer
? function create_buffer_setup() {
return (Writer.create = function create_buffer() {
return new BufferWriter();
})();
}
/* istanbul ignore next */
: function create_array() {
return new Writer();
};
Writer.create = create();

/**
* Allocates a buffer of the specified size.
Expand Down Expand Up @@ -456,4 +460,6 @@ Writer.prototype.finish = function finish() {

Writer._configure = function(BufferWriter_) {
BufferWriter = BufferWriter_;
Writer.create = create();
BufferWriter._configure();
};
47 changes: 24 additions & 23 deletions src/writer_buffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ var Writer = require("./writer");

var util = require("./util/minimal");

var Buffer = util.Buffer;

/**
* Constructs a new buffer writer instance.
* @classdesc Wire format writer using node buffers.
Expand All @@ -19,27 +17,28 @@ function BufferWriter() {
Writer.call(this);
}

/**
* Allocates a buffer of the specified size.
* @param {number} size Buffer size
* @returns {Buffer} Buffer
*/
BufferWriter.alloc = function alloc_buffer(size) {
return (BufferWriter.alloc = util._Buffer_allocUnsafe)(size);
};
BufferWriter._configure = function () {
/**
* Allocates a buffer of the specified size.
* @param {number} size Buffer size
* @returns {Buffer} Buffer
*/
BufferWriter.alloc = util._Buffer_allocUnsafe;

var writeBytesBuffer = Buffer && Buffer.prototype instanceof Uint8Array && Buffer.prototype.set.name === "set"
? function writeBytesBuffer_set(val, buf, pos) {
buf.set(val, pos); // faster than copy (requires node >= 4 where Buffers extend Uint8Array and set is properly inherited)
// also works for plain array values
}
/* istanbul ignore next */
: function writeBytesBuffer_copy(val, buf, pos) {
if (val.copy) // Buffer values
BufferWriter.writeBytesBuffer = util.Buffer && util.Buffer.prototype instanceof Uint8Array && util.Buffer.prototype.set.name === "set"
? function writeBytesBuffer_set(val, buf, pos) {
buf.set(val, pos); // faster than copy (requires node >= 4 where Buffers extend Uint8Array and set is properly inherited)
// also works for plain array values
}
/* istanbul ignore next */
: function writeBytesBuffer_copy(val, buf, pos) {
if (val.copy) // Buffer values
val.copy(buf, pos, 0, val.length);
else for (var i = 0; i < val.length;) // plain array values
else for (var i = 0; i < val.length;) // plain array values
buf[pos++] = val[i++];
};
};
};


/**
* @override
Expand All @@ -50,22 +49,22 @@ BufferWriter.prototype.bytes = function write_bytes_buffer(value) {
var len = value.length >>> 0;
this.uint32(len);
if (len)
this._push(writeBytesBuffer, len, value);
this._push(BufferWriter.writeBytesBuffer, len, value);
return this;
};

function writeStringBuffer(val, buf, pos) {
if (val.length < 40) // plain js is faster for short strings (probably due to redundant assertions)
util.utf8.write(val, buf, pos);
else
buf.utf8Write(val, pos);
buf.utf8Write ? buf.utf8Write(val, pos) : buf.write(val, pos);
}

/**
* @override
*/
BufferWriter.prototype.string = function write_string_buffer(value) {
var len = Buffer.byteLength(value);
var len = util.Buffer.byteLength(value);
this.uint32(len);
if (len)
this._push(writeStringBuffer, len, value);
Expand All @@ -79,3 +78,5 @@ BufferWriter.prototype.string = function write_string_buffer(value) {
* @function
* @returns {Buffer} Finished buffer
*/

BufferWriter._configure();
89 changes: 89 additions & 0 deletions tests/comp_bytes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
var tape = require("tape");

var protobuf = require("..");

var oldBufferImpl = Buffer.alloc === undefined;

// extends Buffer
(CustomBuffer.prototype = Object.create(Buffer.prototype)).constructor = CustomBuffer;

function CustomBuffer(arg, encodingOrOffset, length) {
Buffer.call(this, arg, encodingOrOffset, length);
CustomBuffer.toCustom(this);
}

CustomBuffer.isBuffer = Buffer.isBuffer.bind(Buffer);

CustomBuffer.toCustom = function (b) {
b._isCustom = true;
return b;
}

CustomBuffer.isCustom = function (b) {
return !!b._isCustom;
}

CustomBuffer.from = function (valueOf, encodingOrOffset, length) {
return CustomBuffer.toCustom(oldBufferImpl
? new Buffer(valueOf, encodingOrOffset, length)
: Buffer.from(valueOf, encodingOrOffset, length)
);
}

CustomBuffer.alloc = function (size, fill, encoding) {
return CustomBuffer.toCustom(oldBufferImpl
? new Buffer(size, fill, encoding)
: Buffer.alloc(size, fill, encoding)
);
}

CustomBuffer.allocUnsafe = function (size) {
return CustomBuffer.toCustom(oldBufferImpl
? new Buffer(size)
: Buffer.allocUnsafe(size)
);
}

CustomBuffer.prototype.slice = function (start, end) {
return CustomBuffer.toCustom(this.slice(start, end));
}

tape.test("configure a custom encoder/decoder for bytes", function(test) {
var oldBuffer = protobuf.util.Buffer;

protobuf.util.Buffer = CustomBuffer;
protobuf.configure();

var root = protobuf.Root.fromJSON({
nested: {
test: {
nested: {
Test: {
fields: {
data: {
type: "bytes",
id: 1
}
}
}
}
}
}
});

var Test = root.lookup("test.Test");

var buffer = Test.encode({
data: CustomBuffer.from('some-data')
}).finish();
test.ok(CustomBuffer.isCustom(buffer), "should encode the message with a custom buffer");

var decoded = Test.decode(buffer);
test.ok(CustomBuffer.isCustom(decoded.data), "should decode `data` into a custom buffer");

protobuf.util.Buffer = oldBuffer;
protobuf.configure();

test.end();

});

0 comments on commit 906ef5a

Please sign in to comment.