UNPKG

struffer

Version:
282 lines 8.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const os_1 = require("os"); const util_1 = require("util"); const common_1 = require("./common"); class StrufferBase { /* * properties to be overridden by derrived classes. * we ignore them in code coverage because they're * never suppossed to be reached. derrived classes * MUST override them. */ /* istanbul ignore next */ get kind() { return 'null'; } /* istanbul ignore next */ get info() { return new Map(); } /* istanbul ignore next */ get order() { return []; } /* istanbul ignore next */ static get byteLength() { return 0; } /* istanbul ignore next */ static get bitLength() { return 0; } /* map-like properties */ get size() { return this.order.length; } get [Symbol.toStringTag]() { // `as 'Map'` to be compatible with Maps (in typescript's view) return `${this.constructor.name}<${this.kind}>`; } constructor(buf, offset = 0) { this.buffer = buf; this.structure = new Proxy(Object.create(null), { get: (self, _prop, recv) => { const prop = String(_prop); if (this.has(prop)) { return this.get(prop); } return undefined; }, set: (self, _prop, val, recv) => { const prop = String(_prop); if (this.has(prop)) { this.set(prop, val); return true; } return false; }, has: (self, _prop) => { const prop = String(_prop); if (this.has(prop)) { return true; } return false; }, deleteProperty: (self, _prop) => { const prop = String(_prop); if (this.has(prop)) { return this.delete(prop); } return false; }, ownKeys: (self) => { return [...this.keys()]; }, getOwnPropertyDescriptor: (self, _prop) => { const prop = String(_prop); if (this.has(prop)) { return { configurable: true, enumerable: true, writable: true, }; } return undefined; }, }); this.offset = offset; } /* * method stubs * same reason for ignoring as the overriden properties */ /* istanbul ignore next */ getBits(name) { return []; } /* istanbul ignore next */ setBits(name, bits) { return; } /* map-like methods we care about */ get(name) { const info = this.info.get(name); if (!info) { return undefined; } const bits = this.getBits(name); /* * this condition is hardware dependent, so it's nearly impossible * to test properly for. let's tell istanbul to ignore it */ /* istanbul ignore next: hardware dependent check */ if (os_1.endianness() === 'LE') { if (info.endianness === common_1.MemberEndianness.BigEndian) { bits.reverse(); } } else /* (endianness() === 'BE') */ { if (info.endianness === common_1.MemberEndianness.LittleEndian) { bits.reverse(); } } if (info.signature === common_1.MemberSignature.Signed) { return common_1.joinSignedBits(bits); } return common_1.joinBits(bits); } set(name, value) { const info = this.info.get(name); if (!info) { throw new Error('Structure member not found!'); } let bits = common_1.splitIntoBits(value, false); // same reason as the endianness check in `get` /* istanbul ignore next: hardware dependent check */ if (os_1.endianness() === 'LE') { bits = bits.join('') .padStart(info.bitSize, (value < 0) ? '1' : '0') .split('') .map(i => (i === '0') ? 0 : 1); if (info.endianness === common_1.MemberEndianness.BigEndian) { bits.reverse(); } } else /* (endianness() === 'BE') */ { bits = bits.join('') .padEnd(info.bitSize, (value < 0) ? '1' : '0') .split('') .map(i => (i === '0') ? 0 : 1); if (info.endianness === common_1.MemberEndianness.LittleEndian) { bits.reverse(); } } this.setBits(name, bits); return this; } has(name) { return this.info.has(name); } /* map-like methods we don't care about (i.e. only implemented for compatability) */ delete(name) { if (this.has(name)) { this.set(name, 0); return true; } return false; } clear() { this.deleteMany(this.order.slice()); } forEach(cb, thisArg) { for (const member of this.order) { // override strict undefined check here, we know it exists const value = this.get(member); if (thisArg !== undefined) { cb.call(thisArg, value, member, this); } else { cb(value, member, this); } } } /* batch methods for convenience */ getMany(members = this.order.slice()) { const dict = {}; for (const member of members) { dict[member] = this.get(member); } return dict; } setMany(dictionary) { for (const member of Object.keys(dictionary)) { // override strict undefined check here, we know it exists this.set(member, dictionary[member]); } } hasMany(members) { const table = {}; for (const member of members) { table[member] = this.has(member); } return table; } deleteMany(members) { let result = true; for (const member of members) { const tmp = this.delete(member); if (result) result = tmp; } return result; } /* iterators */ *keys() { /* * it would be easier to use `Array.prototype.values` here, * but for some reason, Node doesn't have it! */ for (const member of this.order) { yield member; } } *values() { for (const member of this.order) { // override strict undefined check here, we know it exists yield this.get(member); } } *entries() { for (const member of this.order) { // same here yield [member, this.get(member)]; } } [Symbol.iterator]() { return this.entries(); } *bits() { for (const member of this.order) { yield this.getBits(member); } } *bitEntries() { for (const member of this.order) { yield [member, this.getBits(member)]; } } /* string representations */ toString() { let str = `${this.constructor.name}<${this.kind}> {\n`; for (const member of this.order) { // override strict undefined check here, we know it exists const info = this.info.get(member); str += ' '; str += member; str += ': '; str += (info.signature === common_1.MemberSignature.Signed) ? 'i' : 'u'; str += info.bitSize; str += (info.endianness === common_1.MemberEndianness.BigEndian) ? 'be' : ''; str += ' = '; str += this.get(member); str += ';\n'; } str += '}'; return str; } [Symbol.toPrimitive](hint) { if (hint === 'number') { throw new TypeError(`Cannot convert ${this.constructor.name}<${this.kind}> to a Number`); } else { return this.toString(); } } [util_1.inspect.custom](depth, opts) { // TODO: stylize for node return this.toString(); } } exports.default = StrufferBase; //# sourceMappingURL=base.js.map