Skip to content
This repository was archived by the owner on Jan 13, 2025. It is now read-only.

Commit 45acd22

Browse files
committed
Merge changes resulting in v0.13.0
2 parents 580aed4 + d923dd0 commit 45acd22

File tree

6 files changed

+182
-13
lines changed

6 files changed

+182
-13
lines changed

CHANGELOG.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
# Change Log
22

3-
## [0.12.1] - 2016-0308
3+
## [0.13.0] - 2016-03-27
4+
5+
* **API** Add [fieldFor][doc:BitStructure.fieldFor].
6+
* Fix incorrect encoding of [boolean-valued bit fields][doc:Boolean].
7+
* **API** Add [offsetOf][doc:Structure.offsetOf] and [layoutFor][doc:Structure.layoutFor].
8+
9+
## [0.12.1] - 2016-03-08
410

511
* Disable coverage testing for [patchIssue3992][doc:patchIssue3992] to
612
avoid taking a penalty on node versions that have been updated.
713

8-
## [0.12.0] - 2016-0308
14+
## [0.12.0] - 2016-03-08
915

1016
* **API** Replace `setClassLayout` with [bindConstructorLayout][doc:bindConstructorLayout].
1117
* **API** Replace `objectPrototype` with [makeDestinationObject][doc:makeDestinationObject].
@@ -98,6 +104,7 @@
98104

99105
* Initial release.
100106

107+
[0.13.0]: https://github.com/pabigot/buffer-layout/compare/v0.12.1...v0.13.0
101108
[0.12.0]: https://github.com/pabigot/buffer-layout/compare/v0.11.0...v0.12.0
102109
[0.11.0]: https://github.com/pabigot/buffer-layout/compare/v0.10.0...v0.11.0
103110
[0.10.0]: https://github.com/pabigot/buffer-layout/compare/v0.9.0...v0.10.0
@@ -131,6 +138,8 @@
131138
[doc:Sequence]: http://pabigot.github.io/buffer-layout/module-Layout-Sequence.html
132139
[doc:Sequence.count]: http://pabigot.github.io/buffer-layout/module-Layout-Sequence.html#count
133140
[doc:Structure]: http://pabigot.github.io/buffer-layout/module-Layout-Structure.html
141+
[doc:Structure.layoutFor]: http://pabigot.github.io/buffer-layout/module-Layout-Structure.html#layoutFor
142+
[doc:Structure.offsetOf]: http://pabigot.github.io/buffer-layout/module-Layout-Structure.html#offsetOf
134143
[issue#1]: https://github.com/pabigot/buffer-layout/issues/1
135144
[issue#2]: https://github.com/pabigot/buffer-layout/issues/2
136145
[issue#3]: https://github.com/pabigot/buffer-layout/issues/3

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ The buffer-layout way:
7979
var ds = lo.struct([lo.u8('v'),
8080
lo.seq(lo.u8(), 3), // alignment padding
8181
lo.u32('u32')]);
82+
assert.equal(ds.offsetOf('u32'), 4);
8283
var b = new Buffer(8);
8384
b.fill(0xbd);
8485
assert.equal(ds.encode({v: 1, u32: 0x12345678}, b), 1 + 3 + 4);
@@ -105,6 +106,7 @@ The buffer-layout way:
105106

106107
var ds = lo.struct([lo.u8('v'),
107108
lo.u32('u32')]);
109+
assert.equal(ds.offsetOf('u32'), 1);
108110
var b = new Buffer(5);
109111
b.fill(0xbd);
110112
assert.equal(ds.encode({v: 1, u32: 0x12345678}, b), 1 + 4);

lib/Layout.js

Lines changed: 93 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,19 @@ Layout.prototype.encode = function(src, b, offset) {
289289
throw new Error('Layout is abstract');
290290
};
291291

292+
/* Provide text that carries a name (such as for a function that will
293+
* be throwing an error) annotated with the property of a given layout
294+
* (such as one for which the value was unacceptable).
295+
*
296+
* @ignore */
297+
function nameWithProperty(name, lo) {
298+
if (lo.property) {
299+
return name + '[' + lo.property + ']';
300+
}
301+
return name;
302+
}
303+
exports.nameWithProperty = nameWithProperty;
304+
292305
/**
293306
* Calculate the span of a specific instance of a layout.
294307
*
@@ -1286,6 +1299,54 @@ Structure.prototype.fromArray = function(values) {
12861299
});
12871300
return dest;
12881301
};
1302+
/**
1303+
* Get access to the layout of a given property.
1304+
*
1305+
* @param {String} property - the structure member of interest.
1306+
*
1307+
* @return {Layout} - the layout associated with `property`, or
1308+
* undefined if there is no such property.
1309+
*/
1310+
Structure.prototype.layoutFor = function(property) {
1311+
var rv;
1312+
if (property) {
1313+
this.fields.forEach(function(fd) {
1314+
if (fd.property === property) {
1315+
rv = fd;
1316+
}
1317+
});
1318+
}
1319+
return rv;
1320+
};
1321+
1322+
/**
1323+
* Get the offset of a structure member.
1324+
*
1325+
* @param {String} property - the structure member of interest.
1326+
*
1327+
* @return {Number} - the offset in bytes to the start of `property`
1328+
* within the structure, or undefined if `property` is not a field
1329+
* within the structure. If the property is a member but follows a
1330+
* variable-length structure member a negative number will be
1331+
* returned.
1332+
*/
1333+
Structure.prototype.offsetOf = function(property) {
1334+
var rv;
1335+
var offset = 0;
1336+
if (property) {
1337+
this.fields.forEach(function(fd) {
1338+
if (fd.property === property) {
1339+
rv = offset;
1340+
}
1341+
if (0 > fd.span) {
1342+
offset = -1;
1343+
} else if (0 <= offset) {
1344+
offset += fd.span;
1345+
}
1346+
});
1347+
}
1348+
return rv;
1349+
};
12891350

12901351
/**
12911352
* An object that can provide a {@link
@@ -1963,6 +2024,25 @@ BitStructure.prototype.addBoolean = function(property) {
19632024
this.fields.push(bf);
19642025
return bf;
19652026
};
2027+
/**
2028+
* Get access to the bit field for a given property.
2029+
*
2030+
* @param {String} property - the bit field of interest.
2031+
*
2032+
* @return {BitField} - the field associated with `property`, or
2033+
* undefined if there is no such property.
2034+
*/
2035+
BitStructure.prototype.fieldFor = function(property) {
2036+
var rv;
2037+
if (property) {
2038+
this.fields.forEach(function(fd) {
2039+
if (fd.property === property) {
2040+
rv = fd;
2041+
}
2042+
});
2043+
}
2044+
return rv;
2045+
};
19662046

19672047
/**
19682048
* Represent a sequence of bits within a {@link
@@ -2057,7 +2137,8 @@ BitField.prototype.decode = function() {
20572137
BitField.prototype.encode = function(value) {
20582138
if ((!Number.isInteger(value))
20592139
|| (value != fixBitwiseResult(value & this.valueMask))) {
2060-
throw new Error('value must be integer not exceeding ' + this.valueMask);
2140+
throw new TypeError(nameWithProperty('BitField.encode', this)
2141+
+ ' value must be integer not exceeding ' + this.valueMask);
20612142
}
20622143
var word = this.container._packedGetValue();
20632144
var wordValue = fixBitwiseResult(value << this.start);
@@ -2084,16 +2165,22 @@ BitField.prototype.encode = function(value) {
20842165
*/
20852166
function Boolean(container, property) {
20862167
BitField.call(this, container, 1, property);
2087-
};
2168+
}
20882169
util.inherits(Boolean, BitField);
20892170
/** Override {@link BitField#decode|decode} for {@link Boolean|Boolean}.
20902171
*
20912172
* @returns {boolean} */
20922173
Boolean.prototype.decode = function(b, offset) {
20932174
return !!BitField.prototype.decode.call(this, b, offset);
20942175
};
2095-
/* There is no override for Boolean.encode since the `src` parameter
2096-
* is interpreted as truthy. */
2176+
/** @override */
2177+
Boolean.prototype.encode = function(value) {
2178+
if ('boolean' === typeof value) {
2179+
// BitField requires integer values
2180+
value = +value;
2181+
}
2182+
return BitField.prototype.encode.call(this, value);
2183+
};
20972184

20982185
/**
20992186
* Contain a fixed-length block of arbitrary data, represented as a
@@ -2162,7 +2249,8 @@ Blob.prototype.encode = function(src, b, offset) {
21622249
}
21632250
if (!((src instanceof Buffer)
21642251
&& (span === src.length))) {
2165-
throw new Error('Blob.encode requires (length ' + span + ') Buffer as src');
2252+
throw new TypeError(nameWithProperty('Blob.encode', this)
2253+
+ ' requires (length ' + span + ') Buffer as src');
21662254
}
21672255
if ((offset + span) > b.length) {
21682256
throw new RangeError('encoding overruns Buffer');

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "buffer-layout",
3-
"version": "0.12.1",
3+
"version": "0.13.0",
44
"description": "Translation between JavaScript values and Buffers",
55
"keywords": [
66
"Buffer",

test/LayoutTest.js

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,20 @@ function reversedBuffer(b) {
1010
return new Buffer(ba.reverse());
1111
}
1212

13+
/* Helper to check that a thrown exception is both the expected type
14+
* and carries the expected message. */
15+
function checkError(exc, expect, regex) {
16+
if (expect && !(exc instanceof expect)) {
17+
console.log('checkError failed: exc ' + typeof exc + ' expect ' + expect);
18+
return false;
19+
}
20+
if (regex && !exc.message.match(regex)) {
21+
console.log('checkError failed: msg "' + exc.message + '" nomatch ' + regex);
22+
return false;
23+
}
24+
return true;
25+
}
26+
1327
suite('Layout', function() {
1428
test('#reversedBuffer', function() {
1529
var b = Buffer('0102030405', 'hex');
@@ -809,6 +823,37 @@ suite('Layout', function() {
809823
assert.equal(src.property, 'p');
810824
assert.strictEqual(dst.property, undefined);
811825
});
826+
test('layoutFor', function() {
827+
var u8 = lo.u8('u8');
828+
var s32 = lo.s32('s32');
829+
var cstr = lo.cstr('cstr');
830+
var u16 = lo.u16('u16');
831+
var d = lo.struct([u8, s32, cstr, u16], 's');
832+
assert.strictEqual(d.layoutFor(), undefined);
833+
assert.strictEqual(d.layoutFor('u8'), u8);
834+
assert.strictEqual(d.layoutFor('cstr'), cstr);
835+
assert.strictEqual(d.layoutFor('other'), undefined);
836+
});
837+
test('nameWithProperty', function() {
838+
var s32 = lo.s32('s32');
839+
var u16 = lo.u16('u16');
840+
var d = lo.struct([s32, lo.u16(), u16], 's');
841+
assert.equal(lo.nameWithProperty('struct', d), 'struct[s]');
842+
assert.equal(lo.nameWithProperty('pfx', d.fields[1]), 'pfx');
843+
});
844+
test('offsetOf', function() {
845+
var u8 = lo.u8('u8');
846+
var s32 = lo.s32('s32');
847+
var cstr = lo.cstr('cstr');
848+
var u16 = lo.u16('u16');
849+
var d = lo.struct([u8, s32, cstr, u16], 's');
850+
assert.strictEqual(d.offsetOf(), undefined);
851+
assert.strictEqual(d.offsetOf('u8'), 0);
852+
assert.strictEqual(d.offsetOf('s32'), 1);
853+
assert.strictEqual(d.offsetOf('cstr'), 5);
854+
assert(0 > d.offsetOf('u16'));
855+
assert.strictEqual(d.offsetOf('other'), undefined);
856+
});
812857
});
813858
suite('VariantLayout', function() {
814859
test('invalid ctor', function() {
@@ -1485,6 +1530,17 @@ suite('Layout', function() {
14851530
assert.deepEqual(bs.decode(b), {a1: 0, b4: 9, c11: 0x4F1, d16: 0x8a51});
14861531
assert.equal(Buffer('518af14c', 'hex').compare(b), 0);
14871532
});
1533+
test('fieldFor', function() {
1534+
var d = new lo.BitStructure(lo.u32(), true);
1535+
var b = d.addBoolean('b');
1536+
var b4 = d.addField(4, 'b4');
1537+
var c11 = d.addField(11, 'c11');
1538+
var d16 = d.addField(16, 'd16');
1539+
assert.strictEqual(d.fieldFor(), undefined);
1540+
assert.strictEqual(d.fieldFor('b'), b);
1541+
assert.strictEqual(d.fieldFor('c11'), c11);
1542+
assert.strictEqual(d.fieldFor('other'), undefined);
1543+
});
14881544
test('gap coding', function() {
14891545
var lsb = new lo.BitStructure(lo.u24());
14901546
var msb = new lo.BitStructure(lo.u24(), true);
@@ -1520,8 +1576,20 @@ suite('Layout', function() {
15201576
assert.notStrictEqual(true, obj.v);
15211577
bs.encode({v: 1, b: 1}, b);
15221578
assert.equal(b[0], 3);
1579+
bs.encode({v: 1, b: true}, b);
1580+
assert.equal(b[0], 3);
15231581
bs.encode({v: 0, b: 0}, b);
15241582
assert.equal(b[0], 0);
1583+
bs.encode({v: 0, b: false}, b);
1584+
assert.equal(b[0], 0);
1585+
bs.encode({}, b);
1586+
assert.equal(b[0], 0);
1587+
assert.throws(function() { bs.encode({v: false}, b); },
1588+
function(err) { return checkError(err, TypeError, /BitField.encode\[v\] value must be integer/); });
1589+
assert.throws(function() { bs.encode({v: 1.2}, b); },
1590+
function(err) { return checkError(err, TypeError, /BitField.encode\[v\] value must be integer/); });
1591+
assert.throws(function() { bs.encode({b: 1.2}, b); },
1592+
function(err) { return checkError(err, TypeError, /BitField.encode\[b\] value must be integer/); });
15251593
});
15261594
});
15271595
suite('Blob', function() {
@@ -1796,7 +1864,7 @@ suite('Layout', function() {
17961864
assert.deepEqual(po, p);
17971865
});
17981866
test('bits', function() {
1799-
function Header() { };
1867+
function Header() { }
18001868
Header.prototype.power = function() {
18011869
return ['off', 'lo', 'med', 'hi'][this.pwr];
18021870
};
@@ -1815,25 +1883,25 @@ suite('Layout', function() {
18151883
assert.equal(b.compare(nb), 0);
18161884
});
18171885
test('union', function() {
1818-
function Union() { };
1886+
function Union() { }
18191887
lo.bindConstructorLayout(Union, lo.union(lo.u8('var'), lo.blob(8, 'unk')));
18201888
function VFloat(v) {
18211889
this.f32 = v;
1822-
};
1890+
}
18231891
util.inherits(VFloat, Union);
18241892
lo.bindConstructorLayout(VFloat,
18251893
Union.layout_.addVariant(1, lo.f32(), 'f32'));
18261894
function VCStr(v) {
18271895
this.text = v;
1828-
};
1896+
}
18291897
util.inherits(VCStr, Union);
18301898
lo.bindConstructorLayout(VCStr,
18311899
Union.layout_.addVariant(2, lo.cstr(), 'text'));
18321900
function Struct(u32, u16, s16) {
18331901
this.u32 = u32;
18341902
this.u16 = u16;
18351903
this.s16 = s16;
1836-
};
1904+
}
18371905
function VStruct(v) {
18381906
this.struct = v;
18391907
}

test/examples.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ struct ds {
2323
var ds = lo.struct([lo.u8('v'),
2424
lo.seq(lo.u8(), 3), // alignment padding
2525
lo.u32('u32')]);
26+
assert.equal(ds.offsetOf('u32'), 4);
2627
var b = new Buffer(8);
2728
b.fill(0xbd);
2829
assert.equal(ds.encode({v: 1, u32: 0x12345678}, b), 1 + 3 + 4);
@@ -38,6 +39,7 @@ struct ds {
3839
*/
3940
var ds = lo.struct([lo.u8('v'),
4041
lo.u32('u32')]);
42+
assert.equal(ds.offsetOf('u32'), 1);
4143
var b = new Buffer(5);
4244
b.fill(0xbd);
4345
assert.equal(ds.encode({v: 1, u32: 0x12345678}, b), 1 + 4);

0 commit comments

Comments
 (0)