diff --git a/lib/Layout.js b/lib/Layout.js index 73d6f12..a7db36d 100644 --- a/lib/Layout.js +++ b/lib/Layout.js @@ -124,7 +124,7 @@ if (!Object.assign) { * Layout#encode|encode} or {@link Layout#decode|decode} functions. * * **NOTE** All instances of concrete extensions of this class are - * frozen prior to being returned from the construtor so that state + * frozen prior to being returned from the constructor so that state * relationships between layouts are not inadvertently corrupted. * * @param {Number} span - Default for {@link Layout#span|span}. The @@ -207,6 +207,31 @@ Layout.prototype.replicate = function (property) { return rv; }; +/** Create an object from layout properties and an array of values. + * + * **NOTE** This function returns `undefined` if invoked on a layout + * that does not return its value as an Object. That would generally + * be anything that isn't fundamentally a {@link Structure|Structure}, + * which includes {@link VariantLayout|variant layouts} if they are + * structures, and excludes {@link Union|Union}s. If you want this + * feature for a union you must use {@link + * Union.getVariant|getVariant} to select the desired layout. + * + * @param {Array} values - an array of values that correspond to the + * default order for properties. As with {@link Layout#decode|decode} + * layout elements that have no property name are skipped when + * iterating over the array values. Only the top-level properties are + * assigned; arguments are not assigned to properties of contained + * layouts. Any unused values are ignored. + * + * @param {Object} dest - as with {@link Layout#decode|decode}. If + * required but not provided an empty Object will be used. + * + * @return {(Object|undefined)} */ +Layout.prototype.fromArray = function () { + return undefined; +}; + /** Represent an unsigned integer in little-endian format. * * @param {Number} span - initializer for {@link Layout#span|span}. @@ -591,7 +616,7 @@ Structure.prototype.encode = function (src, b, offset) { if (undefined === offset) { offset = 0; } - this.fields.map(function (fd) { + this.fields.forEach(function (fd) { if (undefined !== fd.property) { var fv = src[fd.property]; if (undefined === fv) { @@ -603,6 +628,20 @@ Structure.prototype.encode = function (src, b, offset) { offset += fd.span; }); }; +/** Implement {@link Layout#fromArray|fromArray} for {@link + * Structure|Structure}. */ +Structure.prototype.fromArray = function (values, dest) { + if (undefined === dest) { + dest = {}; + } + this.fields.forEach(function (fd) { + if ((undefined !== fd.property) + && (0 < values.length)) { + dest[fd.property] = values.shift(); + } + }); + return dest; +}; /** Represent any number of span-compatible layouts. * @@ -856,6 +895,14 @@ VariantLayout.prototype.encode = function (src, b, offset) { dlo.encode(this.variant, b, offset); this.layout.encode(src, b, offset + dlo.span); }; +/** Implement {@link Layout#fromArray|fromArray} for {@link + * VariantLayout|VariantLayout}. */ +VariantLayout.prototype.fromArray = function (values, dest) { + if (this.layout instanceof Structure) { + return this.layout.fromArray(values, dest); + } + return undefined; +}; exports.Layout = Layout; exports.UInt = UInt; diff --git a/test/LayoutTest.js b/test/LayoutTest.js index eca7f9b..21bfd69 100644 --- a/test/LayoutTest.js +++ b/test/LayoutTest.js @@ -529,4 +529,17 @@ suite("Layout", function () { assert.equal('payload', un.layout.fields[1].property); }); }); + test("fromArray", function () { + assert.strictEqual(undefined, lo.u8().fromArray([1])); + var st = new lo.Structure([lo.u8('a'), lo.u8('b'), lo.u16('c')]); + assert(_.isEqual({a:1, b:2, c:3}, st.fromArray([1,2,3]))); + assert(_.isEqual({a:1, b:2}, st.fromArray([1,2]))); + var un = new lo.Union(lo.u8('v'), lo.u32('c')); + assert.strictEqual(undefined, un.fromArray([1,2,3])); + var v1 = un.addVariant(1, st), + v2 = un.addVariant(2, lo.f32()); + assert(v1 instanceof lo.VariantLayout); + assert(_.isEqual({a:1, b:2, c:3}, un.getVariant(1).fromArray([1,2,3]))); + assert.strictEqual(undefined, un.getVariant(2).fromArray([1,2,3])); + }); });