Skip to content

Commit

Permalink
Layout: document optional destination parameter to decode
Browse files Browse the repository at this point in the history
This feature was stubbed but neither documented nor completed.

Closes issue #2
  • Loading branch information
pabigot committed Oct 25, 2015
1 parent 887537f commit fa505d1
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 12 deletions.
34 changes: 26 additions & 8 deletions lib/Layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,14 @@ function Layout (span, property) {
* @param {Number} [offset] - the offset at which the encoded data
* starts. If absent a zero offset is inferred.
*
* @returns {(Number|Object)} - the value of the decoded data. */
* @param {Object} [dest] - the Object into which properties will be
* assigned. This only applies to {@link Structure|Structure} layouts
* (including the {@link Union#layout|default Union layout} and
* compatible {@link VariantLayout|variant layouts}) since other
* layouts return non-Object results. If required but not provided an
* empty Object will be used as the destination.
*
* @returns {(Number|Array|Object)} - the value of the decoded data. */
Layout.prototype.decode = function () {
throw new Error('Layout is abstract');
};
Expand Down Expand Up @@ -555,7 +562,11 @@ function Structure (fields, property) {
}
Structure.prototype = Object.create(Layout.prototype);
Structure.prototype.constructor = Structure;
/** Implement {@link Layout#decode|decode} for {@link Structure|Structure}. */
/** Implement {@link Layout#decode|decode} for {@link Structure|Structure}.
*
* This layout makes use the `dest` parameter, allowing decoded
* properties to be stored directly into an existing object (e.g. when
* used in an object constructor). */
Structure.prototype.decode = function (b, offset, dest) {
if (undefined === dest) {
dest = {};
Expand Down Expand Up @@ -690,18 +701,25 @@ function Union (discr_layout,
Union.prototype = Object.create(Layout.prototype);
Union.prototype.constructor = Union;
/** Implement {@link Layout#decode|decode} for {@link Union|Union}. */
Union.prototype.decode = function (b, offset) {
Union.prototype.decode = function (b, offset, dest) {
if (undefined === offset) {
offset = 0;
}
if (undefined === dest) {
dest = {};
}
var dlo = this.discr_layout,
discr = dlo.decode(b, offset),
vlo = this.registry[discr];
if (undefined === vlo) {
return { variant: discr,
content: this.default_layout.decode(b, offset + dlo.span) };
var dpr = this.layout.fields[0].property,
cpr = this.layout.fields[1].property;
dest[dpr] = discr;
dest[cpr] = this.default_layout.decode(b, offset + dlo.span);
} else {
dest = vlo.decode(b, offset, dest);
}
return vlo.decode(b, offset);
return dest;
};
/** Implement {@link Layout#encode|encode} for {@link Union|Union}. */
Union.prototype.encode = function (src, b, offset) {
Expand Down Expand Up @@ -819,15 +837,15 @@ function VariantLayout (union,
VariantLayout.prototype = Object.create(Layout.prototype);
VariantLayout.prototype.constructor = VariantLayout;
/** Implement {@link Layout#decode|decode} for {@link VariantLayout|VariantLayout}. */
VariantLayout.prototype.decode = function (b, offset) {
VariantLayout.prototype.decode = function (b, offset, dest) {
if (undefined === offset) {
offset = 0;
}
var dlo = this.union.discr_layout;
if (this !== this.union.getVariant(b, offset)) {
throw new Error("variant mismatch");
}
return this.layout.decode(b, offset + dlo.span);
return this.layout.decode(b, offset + dlo.span, dest);
};
/** Implement {@link Layout#encode|encode} for {@link VariantLayout|VariantLayout}. */
VariantLayout.prototype.encode = function (src, b, offset) {
Expand Down
19 changes: 15 additions & 4 deletions test/LayoutTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -476,11 +476,17 @@ suite("Layout", function () {
assert.equal(0, Buffer('050000000300000007', 'hex').compare(b));
});
test("variants", function () {
var dlo = lo.u8(),
vlo = new lo.Sequence(lo.u8(), 4),
var dlo = lo.u8('v'),
vlo = new lo.Sequence(lo.u8(), 4, 'c'),
un = new lo.Union(dlo, vlo),
b = new Buffer(5);
assert.strictEqual(undefined, un.getVariant(1));
b.fill(0);
assert(_.isEqual({v: 0, c:[0,0,0,0]}, un.decode(b)));
var obj = { destination: true },
rv = un.decode(b, 0, obj);
assert.strictEqual(rv, obj);
assert(_.isEqual({v: 0, c:[0,0,0,0], destination:true}, obj));
var lo1 = lo.u32(),
v1 = un.addVariant(1, lo1);
assert(v1 instanceof lo.VariantLayout);
Expand All @@ -490,6 +496,9 @@ suite("Layout", function () {
assert.strictEqual(v1, un.getVariant(b));
assert.equal(0x01010101, v1.decode(b));
assert.equal(0x01010101, un.decode(b));
obj = { destination: true };
rv = un.decode(b, 0, obj);
assert.equal(0x01010101, rv);
var lo2 = lo.f32(),
v2 = un.addVariant(2, lo2);
un.discr_layout.encode(v2.variant, b);
Expand All @@ -502,8 +511,10 @@ suite("Layout", function () {
assert.strictEqual(v3, un.getVariant(b));
assert(_.isEqual({a:1, b:1, c:257}, v3.decode(b)));
assert(_.isEqual({a:1, b:1, c:257}, un.decode(b)));
un.discr_layout.encode(99, b);
assert(_.isEqual({variant:99, content:[1,1,1,1]}, un.decode(b)));
obj = { destination: true };
rv = un.decode(b, 0, obj);
assert.strictEqual(rv, obj);
assert(_.isEqual({a:1, b:1, c:257, destination:true}, rv));
})
test("custom default", function () {
var dlo = lo.u8('number'),
Expand Down

0 comments on commit fa505d1

Please sign in to comment.