Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for buffer configuration. #1257

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();

});