UNPKG

bitbit

Version:

JavaScript Object to Bits Utility

152 lines (119 loc) 4.71 kB
/** * BIT BIT Conversion Library * Author: Jason Carter 2017 * * Revisions: * 05/2017: Jason Carter */ const _ = require('lodash'); const assert = require('assert'); const debug = require('debug')('bitbit'); class BitBit { constructor(schema) { validateSchema(schema); this.schema = schema; } /** * Converts an object down to a decimal number based on the bit mappings * in the schema * * @param {object} objToConvert * @returns {number} */ pack(objToConvert) { if (!this.schema) throw new Error('No Schema Exists!'); if (_.isNil(objToConvert)) { debug('Object to Convert was null or undefined - returning zero'); return 0; } let retValue = 0; // Get all keys from the schema to convert const keysToConvert = _.keys(this.schema); _.each(keysToConvert, (k) => { const bitInfo = this.schema[k]; let valueToConvert = _.get(objToConvert, k); // For now skip anything that is not a number or boolean if (!_.isInteger(valueToConvert) && !_.isBoolean(valueToConvert)) return; // Coerce Booleans to Numbers (0, 1) valueToConvert = +valueToConvert; // Get the bit info - default the second bit value to the first one // if no second one was specified - this means it's a single bit value const firstBitLocation = bitInfo[0]; const secondBitLocation = bitInfo[1] || bitInfo[0]; const maxBits = secondBitLocation - firstBitLocation + 1; // Number to & the result with to limit to maxBits // For example if you have a single bit available - you can only have 1 or 0 // passing in 3 will convert it to 1 through (1 & 3) const limiter = parseInt(_.repeat('1', maxBits), 2); debug(`For field: ${k}: First Bit: ${firstBitLocation} Last Bit: ${secondBitLocation} Maximum Bits: ${maxBits} Number to '&' with: ${limiter} `); // Convert the value to a bitmask integer value let bitValue = (valueToConvert & limiter) << firstBitLocation; debug(`Got Bit Value: ${bitValue} by function: (${valueToConvert} & ${limiter}) << ${firstBitLocation}`); retValue += bitValue; }); return retValue; } /** * Converts a standard decimal number to the object based on the Schema * * @param {number} numToConvert * @returns {object} */ unpack(numToConvert) { if (!this.schema) throw new Error('No Schema Exists!'); if (_.isNil(numToConvert)) { debug('Number to Convert to Object is null or undefined - returning blank object'); return {}; } let retObj = {}; const keysToConvert = _.keys(this.schema); _.each(keysToConvert, (k) => { const bitInfo = this.schema[k]; // Get the bit info - default the second bit value to the first one // if no second one was specified - this means it's a single bit value const firstBitLocation = bitInfo[0]; const secondBitLocation = bitInfo[1] || bitInfo[0]; const maxBits = secondBitLocation - firstBitLocation + 1; // Number to & the result with to limit to maxBits // For example if you have a single bit available - you can only have 1 or 0 // passing in 3 will convert it to 1 through (1 & 3) const limiter = parseInt(_.repeat('1', maxBits), 2); const isBoolean = _.isNil(bitInfo[1]) ? true : false; let valShifted = (numToConvert >> firstBitLocation) & limiter; if (isBoolean) valShifted = valShifted === 1 ? true : false; _.set(retObj, k, valShifted); }); return retObj; } } /** * Validate the Schema given * Schema must be a single level object where every key * maps to an array of 1 or 2 integers * * @param {object} schema * @returns {boolean} */ function validateSchema(schema) { if (!schema) throw new Error('A Schema must be supplied'); if (!_.isPlainObject(schema)) throw new Error('Schema must be an object'); if (_.size(schema) <= 0) throw new Error('Schema must have more than 1 key'); _.each(schema, (val) => { assert(Array.isArray(val), 'Value of Key must be an array.'); assert((_.size(val) === 1 || _.size(val) === 2), 'Value Array must have 1 or 2 values'); assert(_.isNumber(val[0]), 'First value in the array must be a number'); if (val[1]) { assert(_.isNumber(val[1]), 'If given, second value in the array must be a number'); assert(val[1] >= val[0], 'Value 2 if given must be greater than or equal to Value 1'); } }); // TODO - validate the schema has no overlapping bit fields // i.e { "val1": [0, 4], "val2": [2, 6] } // currently this will just break } module.exports = BitBit;