reign
Version:
A persistent, typed-objects implementation.
238 lines (209 loc) • 7.49 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.MIN_TYPE_ID = undefined;
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
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 }; }
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var MIN_TYPE_ID = exports.MIN_TYPE_ID = Math.pow(2, 20) * 8;function make(realm) {
var TypeClass = realm.TypeClass;
var 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 function (Union) {
typeCounter++;
var name = possibleTypes.map(function (PossibleType) {
return PossibleType.name;
}).join(' | ');
var id = MIN_TYPE_ID + typeCounter;
Union[_symbols.$CanBeEmbedded] = true;
Union[_symbols.$CanBeReferenced] = false;
Union[_symbols.$CanContainReferences] = possibleTypes.some(function (type) {
return type[_symbols.$CanContainReferences];
});
var byteAlignment = Math.max.apply(Math, [4].concat(_toConsumableArray(possibleTypes.map(function (type) {
return type.byteAlignment;
}))));
var byteLength = (0, _util.alignTo)(Math.max.apply(Math, _toConsumableArray(possibleTypes.map(function (type) {
return type.byteLength;
}))) + 4, byteAlignment);
var idOffset = byteLength - 4;
var UnionArray = void 0;
// Issue 285
Object.defineProperties(Union, {
Array: {
get: function get() {
if (UnionArray === undefined) {
UnionArray = new realm.ArrayType(Union);
}
return UnionArray;
}
}
});
var prototype = Object.create(null, {
// Issue 285
value: {
enumerable: true,
get: function get() {
var backing = this[_symbols.$Backing];
var address = this[_symbols.$Address];
var typeId = backing.getUint32(address + idOffset);
if (typeId === 0) {
return null;
} else {
return realm.I[typeId].load(backing, address);
}
},
set: function set(value) {
var backing = this[_symbols.$Backing];
var address = this[_symbols.$Address];
storeUnion(backing, address, value);
}
},
// Issue 285
type: {
enumerable: true,
get: function get() {
var 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() {
var value = this.value;
if (value != null && (typeof value === "undefined" ? "undefined" : _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 {
var 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 (var i = 0; i < possibleTypes.length; i++) {
var 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 {
var type = typeFor(initialValue);
type.initialize(backing, address, initialValue);
backing.setUint32(address + idOffset, type.id);
}
}
function storeUnion(backing, address, value) {
var 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 {
var type = typeFor(value);
type.initialize(backing, address, value);
backing.setUint32(address + idOffset, type.id);
}
}
function loadUnion(backing, address) {
var typeId = backing.getUint32(address + idOffset);
if (typeId === 0) {
return null;
} else {
return realm.I[typeId].load(backing, address);
}
}
function clearUnion(backing, address) {
var typeId = backing.getUint32(address + idOffset);
if (typeId !== 0) {
backing.setUint32(backing, address + idOffset, 0);
realm.I[typeId].clear(backing, address);
}
}
function unionDestructor(backing, address) {
var typeId = backing.getUint32(address + idOffset);
if (typeId !== 0) {
realm.I[typeId].clear(backing, address);
}
}
function typeFor(input) {
for (var i = 0; i < possibleTypes.length; i++) {
var 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);
}
};
};
});
};