UNPKG

reign

Version:

A persistent, typed-objects implementation.

205 lines (176 loc) 6.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); 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.make = make; var _any = require("../../hash-functions/any"); var _any2 = _interopRequireDefault(_any); var _backing = require("backing"); var _backing2 = _interopRequireDefault(_backing); var _ = require("../.."); var _symbols = require("../../symbols"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function make(realm) { var ObjectType = realm.ObjectType; var T = realm.T; function constructor(backingOrInput, address) { if (!(this instanceof TypedObject)) { return TypedObject.cast(backingOrInput); } if (backingOrInput instanceof _backing2.default) { this[_symbols.$Backing] = backingOrInput; this[_symbols.$Address] = address; createAccessors(this); } else if (backingOrInput == null) { this[_symbols.$Backing] = realm.backing; this[_symbols.$Address] = createEmptyObject(realm.backing); } else { this[_symbols.$Backing] = realm.backing; this[_symbols.$Address] = createObject(realm.backing, backingOrInput); // @fixme we should combine createObject and createAccessors to make this faster. createAccessors(this); } } var TypedObject = new ObjectType({ name: 'Object', byteAlignment: 8, // Pointer byteLength: 8, constructor: constructor, cast: function cast(input) { return input == null ? null : Object(input); }, accepts: function accepts(input) { return (typeof input === "undefined" ? "undefined" : _typeof(input)) === 'object'; }, initialize: function initialize(backing, pointerAddress, initialValue) { if (initialValue == null) { backing.setFloat64(pointerAddress, 0); } else { backing.setFloat64(pointerAddress, createObject(backing, initialValue, true)); } }, store: function store(backing, pointerAddress, value) { var existing = backing.getFloat64(pointerAddress); if (existing === 0) { if (value == null) { // nothing to do return; } } else { backing.gc.unref(existing); backing.setFloat64(pointerAddress, 0); // safety: in case the store() fails. if (value == null) { // all done return; } } backing.setFloat64(pointerAddress, createObject(backing, value, true)); }, load: function load(backing, pointerAddress) { var address = backing.getFloat64(pointerAddress); if (address === 0) { return null; } else { return new TypedObject(backing, address); } }, clear: function clear(backing, pointerAddress) { var address = backing.getFloat64(pointerAddress); if (address !== 0) { backing.setFloat64(pointerAddress, 0); backing.gc.unref(address); } }, destructor: destroyObject, emptyValue: function emptyValue() { return null; }, randomValue: function randomValue() { return null; }, hashValue: _any2.default, flowType: function flowType() { return "Object"; } }); function createAccessors(target) { var backing = target[_symbols.$Backing]; var address = target[_symbols.$Address]; var length = backing.getUint32(address); var current = address + 8; var _loop = function _loop(i) { var name = T.String.load(backing, current); var offset = current + 8; Object.defineProperty(target, name, { enumerable: true, get: function get() { return T.Any.load(this[_symbols.$Backing], offset); }, set: function set(value) { T.Any.store(this[_symbols.$Backing], offset, value); } }); current += 24; }; for (var i = 0; i < length; i++) { _loop(i); } } function createEmptyObject(backing, hasReference) { return backing.gc.calloc(8, TypedObject.id, hasReference ? 1 : 0); } function createObject(backing, input, hasReference) { if (input instanceof TypedObject && input[_symbols.$Backing] === backing) { backing.gc.ref(input[_symbols.$Address]); return input[_symbols.$Address]; } var keys = Object.keys(input); var length = keys.length; var address = backing.gc.alloc(length * 24 + 8, TypedObject.id, hasReference ? 1 : 0); backing.setUint32(address, length); var current = address + 8; for (var i = 0; i < length; i++) { var key = keys[i]; backing.setFloat64(current, realm.strings.add(key)); current += 8; T.Any.initialize(backing, current, input[key]); current += 16; } return address; } function loadObject(backing, address) { var _output; var output = (_output = {}, _defineProperty(_output, _symbols.$Backing, backing), _defineProperty(_output, _symbols.$Address, address), _output); var length = backing.getUint32(address); var current = address + 8; for (var i = 0; i < length; i++) { output[T.String.load(backing, current)] = T.Any.load(backing, current + 8); current += 24; } return output; } function clearObject(backing, address) { var length = backing.getUint32(address); var current = address + 8; for (var i = 0; i < length; i++) { current += 8; T.Any.clear(backing, current); current += 16; } } function destroyObject(backing, address) { var length = backing.getUint32(address); backing.setUint32(address, 0); // prevent further reads. var current = address + 8; for (var i = 0; i < length; i++) { backing.setFloat64(current, 0); current += 8; T.Any.clear(backing, current); current += 16; } } TypedObject[_symbols.$CanBeEmbedded] = false; return TypedObject; }