/**
* @author Toru Nagashima
* @copyright 2016 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
*/
"use strict"
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const assert = require("./assert")
//------------------------------------------------------------------------------
// Helpers
//------------------------------------------------------------------------------
const BUFFER = Symbol("buffer")
const SUB_RECORDS = Symbol("subRecords")
/**
* BinaryRecord class is the base class for all binary record types.
*
* This class cannot be directly instantiated.
* It needs to define subclasses with {@link module:bre.defineObjectRecord} or
* {@link module:bre.defineArrayRecord}.
*
* @memberof module:bre
*/
class BinaryRecord {
/**
* This class cannot be directly instantiated. It needs to define subclasses
* with `bre.defineObjectRecord` or `bre.defineArrayRecord`.
*
* @param {ArrayBuffer|DataView|TypedArray} buffer - The buffer to wrap.
* @param {number|undefined} byteOffset - The start position to wrap.
* @private
*/
constructor(buffer, byteOffset) {
if (byteOffset === undefined) {
byteOffset = 0 //eslint-disable-line no-param-reassign
}
assert(
this.constructor !== BinaryRecord,
"'BinaryRecord' class cannot be directly instantiated. " +
"Use via 'bre.defineObjectRecord' or 'bre.defineArrayRecord'."
)
assert.integer(
this.constructor.bitLength,
`${this.constructor.name}.bitLength`
)
assert.integer(
this.constructor.byteLength,
`${this.constructor.name}.byteLength`
)
assert.function(
this.constructor.keys,
`${this.constructor.name}.keys`
)
// Strip Buffer of Node.js
// Buffer of Node.js is one of ArrayBuufer's view.
const rawBuffer = ArrayBuffer.isView(buffer) ? buffer.buffer : buffer
assert.instanceOf(rawBuffer, ArrayBuffer, "buffer")
assert.integer(byteOffset, "byteOffset")
assert.gte(byteOffset, 0, "byteOffset")
const byteLength = this.constructor.byteLength
assert(
buffer.byteLength >= byteOffset + byteLength,
"'buffer' should have enough size for the offset and size of this" +
` record (${byteOffset} + ${byteLength} = ` +
`${byteOffset + byteLength}), but got ${buffer.byteLength}.`
)
this[BUFFER] = new DataView(
rawBuffer,
buffer.byteOffset + byteOffset,
byteLength
)
}
/**
* Gets length in bits of the given record.
*
* const bits = bre.BinaryRecord.bitLength(record1)
* console.log(bits) // => 16
*
* @param {module:bre.BinaryRecord} record - The record to get.
* @returns {number} The length in bits of the record.
*/
static bitLength(record) {
assert.instanceOf(record, BinaryRecord, "record")
return record.constructor.bitLength
}
/**
* Gets length in bytes of the given record.
*
* const bytes = bre.BinaryRecord.byteLength(record1)
* console.log(bytes) // => 2
*
* @param {module:bre.BinaryRecord} record - The record to get.
* @returns {number} The length in bytes of the record.
*/
static byteLength(record) {
assert.instanceOf(record, BinaryRecord, "record")
return record.constructor.byteLength
}
/**
* Gets the keys of the given record.
*
* [Object.keys](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/keys)
* does not work for records because the properties of records are
* getter/setter pairs in the prototype. Use this method instead.
*
* const keys = bre.BinaryRecord.keys(record1)
* console.log(keys) // => ["a", "b"]
*
* @param {module:bre.BinaryRecord} record - The record to get.
* @returns {IterableIterator<string>} The keys of the record.
*/
static keys(record) {
assert.instanceOf(record, BinaryRecord, "record")
return record.constructor.keys()
}
/**
* Gets the values of the given record.
*
* [Object.values](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/values)
* does not work for records because the properties of records are
* getter/setter pairs in the prototype. Use this method instead.
*
* const values = bre.BinaryRecord.values(record1)
* console.log(values) // => [1, 10]
*
* @param {module:bre.BinaryRecord} record - The record to get.
* @returns {IterableIterator<any>} The values of the record.
*/
static* values(record) {
assert.instanceOf(record, BinaryRecord, "record")
for (const key of record.constructor.keys()) {
yield record[key]
}
}
/**
* Gets the key-value pairs of the given record.
*
* [Object.entries](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/entries)
* does not work for records because the properties of records are
* getter/setter pairs in the prototype. Use this method instead.
*
* const entries = bre.BinaryRecord.entries(record1)
* console.log(entries) // => [ ["a", 1], ["b", 10] ]
*
* @param {module:bre.BinaryRecord} record - The record to get.
* @returns {IterableIterator<any[]>} The key-value pairs of the record.
*/
static* entries(record) {
assert.instanceOf(record, BinaryRecord, "record")
for (const key of record.constructor.keys()) {
yield [key, record[key]]
}
}
}
BinaryRecord.symbols = {
buffer: BUFFER,
subRecords: SUB_RECORDS,
}
//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------
exports.BinaryRecord = BinaryRecord