reign
Version:
A persistent, typed-objects implementation.
225 lines (199 loc) • 6.83 kB
JavaScript
;
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);
}
};
};
});
};