UNPKG

reign

Version:

A persistent, typed-objects implementation.

225 lines (199 loc) 6.83 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MIN_TYPE_ID = undefined; exports. /** * Makes a UnionType type class for the given realm. */ make = make; var _backing = require("backing"); var _backing2 = _interopRequireDefault(_backing); var _ = require("../"); var _util = require("../../util"); var _2 = require("../../"); var _symbols = require("../../symbols"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const MIN_TYPE_ID = exports.MIN_TYPE_ID = Math.pow(2, 20) * 8;function make(realm) { const TypeClass = realm.TypeClass; let typeCounter = 0; return new TypeClass('UnionType', function () { for (var _len = arguments.length, possibleTypes = Array(_len), _key = 0; _key < _len; _key++) { possibleTypes[_key] = arguments[_key]; } return Union => { typeCounter++; const name = possibleTypes.map(PossibleType => PossibleType.name).join(' | '); const id = MIN_TYPE_ID + typeCounter; Union[_symbols.$CanBeEmbedded] = true; Union[_symbols.$CanBeReferenced] = false; Union[_symbols.$CanContainReferences] = possibleTypes.some(type => type[_symbols.$CanContainReferences]); const byteAlignment = Math.max(4, ...possibleTypes.map(type => type.byteAlignment)); const byteLength = (0, _util.alignTo)(Math.max(...possibleTypes.map(type => type.byteLength)) + 4, byteAlignment); const idOffset = byteLength - 4; let UnionArray; // Issue 285 Object.defineProperties(Union, { Array: { get: function get() { if (UnionArray === undefined) { UnionArray = new realm.ArrayType(Union); } return UnionArray; } } }); const prototype = Object.create(null, { // Issue 285 value: { enumerable: true, get: function get() { const backing = this[_symbols.$Backing]; const address = this[_symbols.$Address]; const typeId = backing.getUint32(address + idOffset); if (typeId === 0) { return null; } else { return realm.I[typeId].load(backing, address); } }, set: function set(value) { const backing = this[_symbols.$Backing]; const address = this[_symbols.$Address]; storeUnion(backing, address, value); } }, // Issue 285 type: { enumerable: true, get: function get() { const typeId = this[_symbols.$Backing].getUint32(this[_symbols.$Address] + idOffset); return typeId === 0 ? null : realm.I[typeId]; } }, inspect: { value: function value() { return this.value; } }, valueOf: { value: function value() { return this.value; } }, toJSON: { value: function value() { const value = this.value; if (value != null && typeof value === 'object' && typeof value.toJSON === 'function') { return value.toJSON(); } else { return value; } } } }); function constructor(backingOrInput, address) { if (backingOrInput instanceof _backing2.default) { this[_symbols.$Backing] = backingOrInput; this[_symbols.$Address] = address; } else { const backing = realm.backing; this[_symbols.$Backing] = backing; this[_symbols.$Address] = backing.gc.alloc(byteLength, Union.id); initializeUnion(backing, this[_symbols.$Address], backingOrInput); } } function unionAccepts(input) { for (let i = 0; i < possibleTypes.length; i++) { const type = possibleTypes[i]; if (type.accepts(input)) { return true; } } return false; } function initializeUnion(backing, address, initialValue) { if (initialValue == null) { backing.setUint32(address + idOffset, 0); } else { const type = typeFor(initialValue); type.initialize(backing, address, initialValue); backing.setUint32(address + idOffset, type.id); } } function storeUnion(backing, address, value) { const existing = backing.getUint32(address + idOffset); if (existing !== 0) { realm.I[existing].clear(backing, address); } else if (value == null) { // nothing to do. return; } if (value == null) { backing.setUint32(address + idOffset, 0); } else { const type = typeFor(value); type.initialize(backing, address, value); backing.setUint32(address + idOffset, type.id); } } function loadUnion(backing, address) { const typeId = backing.getUint32(address + idOffset); if (typeId === 0) { return null; } else { return realm.I[typeId].load(backing, address); } } function clearUnion(backing, address) { const typeId = backing.getUint32(address + idOffset); if (typeId !== 0) { backing.setUint32(backing, address + idOffset, 0); realm.I[typeId].clear(backing, address); } } function unionDestructor(backing, address) { const typeId = backing.getUint32(address + idOffset); if (typeId !== 0) { realm.I[typeId].clear(backing, address); } } function typeFor(input) { for (let i = 0; i < possibleTypes.length; i++) { const type = possibleTypes[i]; if (type.accepts(input)) { return type; } } throw new TypeError(`Union does not contain a type which can accept the given input.`); } return { id: id, name: name, byteLength: byteLength, byteAlignment: byteAlignment, constructor: constructor, prototype: prototype, accepts: unionAccepts, initialize: initializeUnion, store: storeUnion, load: loadUnion, clear: clearUnion, destructor: unionDestructor, equal: function equal(a, b) { return typeFor(a).equal(a, b); }, emptyValue: function emptyValue() { return null; }, randomValue: function randomValue() { return possibleTypes[Math.floor(Math.random() * possibleTypes.length)].randomValue(); }, hashValue: function hashValue(input) { return typeFor(input).hashValue(input); } }; }; }); };