reign
Version:
A persistent, typed-objects implementation.
338 lines (305 loc) • 15.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createInitializeStruct = createInitializeStruct;
exports.createStoreStruct = createStoreStruct;
exports.createAccepts = createAccepts;
exports.createToJSON = createToJSON;
exports.createClearStruct = createClearStruct;
exports.createStructDestructor = createStructDestructor;
exports.createCompareAddresses = createCompareAddresses;
exports.createEqual = createEqual;
exports.createCompareValues = createCompareValues;
exports.createCompareAddressValue = createCompareAddressValue;
exports.createHashStruct = createHashStruct;
exports.createRandomValue = createRandomValue;
exports.isValidIdentifier = isValidIdentifier;
var _backing = require("backing");
var _backing2 = _interopRequireDefault(_backing);
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); } }
/**
* Creates a function which can initialize a new struct, either
* via a config object or by using default (empty) field values.
*/
function createInitializeStruct(Partial, fields) {
var defaults = [];
var setValues = fields.map(function (field, index) {
var name = field.name;
var type = field.type;
var offset = field.offset;
defaults.push(field.default);
if (isValidIdentifier(name)) {
return "\n type" + index + ".initialize(backing, address + " + offset + ", (tmp = input." + name + ") !== undefined ? tmp : defaults[" + index + "]());\n ";
} else {
var sanitizedName = JSON.stringify(name);
return "\n type" + index + ".initialize(backing, address + " + offset + ", (tmp = input[" + sanitizedName + "]) !== undefined ? tmp : defaults[" + index + "]());\n ";
}
}).join('');
var setEmpty = fields.map(function (_ref, index) {
var name = _ref.name;
var type = _ref.type;
var offset = _ref.offset;
return "\n type" + index + ".initialize(backing, address + " + offset + ", defaults[" + index + "]());\n ";
}).join('');
var argNames = ['$Address', 'Partial', 'defaults'].concat(_toConsumableArray(fields.map(function (_, index) {
return "type" + index;
})));
var args = [_symbols.$Address, Partial, defaults].concat(_toConsumableArray(fields.map(function (field) {
return field.type;
})));
var body = "\n \"use strict\";\n return function initializeStruct (backing, address, input) {\n if (input == null) {\n " + setEmpty + "\n }\n else if (input instanceof Partial) {\n backing.copy(address, input[$Address], Partial.byteLength);\n }\n else {\n var tmp;\n " + setValues + "\n }\n };\n ";
return Function.apply(undefined, _toConsumableArray(argNames).concat([body])).apply(undefined, _toConsumableArray(args));
}
/**
* Creates a function which can write a struct, either
* via a config object or by using default (empty) field values.
*/
function createStoreStruct(Partial, fields) {
var defaults = [];
var setValues = fields.map(function (field, index) {
var name = field.name;
var type = field.type;
var offset = field.offset;
defaults.push(field.default);
if (isValidIdentifier(name)) {
return "\n type" + index + ".store(backing, address + " + offset + ", (tmp = input." + name + ") !== undefined ? tmp : defaults[" + index + "]);\n ";
} else {
var sanitizedName = JSON.stringify(name);
return "\n type" + index + ".store(backing, address + " + offset + ", (tmp = input[" + sanitizedName + "]) !== undefined ? tmp : defaults[" + index + "]);\n ";
}
}).join('');
var setEmpty = fields.map(function (_ref2, index) {
var name = _ref2.name;
var type = _ref2.type;
var offset = _ref2.offset;
return "\n type" + index + ".store(backing, address + " + offset + ", defaults[" + index + "]);\n ";
}).join('');
var argNames = ['$Address', 'Partial', 'defaults'].concat(_toConsumableArray(fields.map(function (_, index) {
return "type" + index;
})));
var args = [_symbols.$Address, Partial, defaults].concat(_toConsumableArray(fields.map(function (field) {
return field.type;
})));
var body = "\n \"use strict\";\n return function storeStruct (backing, address, input) {\n if (input == null) {\n " + setEmpty + "\n }\n else if (input instanceof Partial) {\n backing.copy(address, input[$Address], Partial.byteLength);\n }\n else {\n var tmp;\n " + setValues + "\n }\n };\n ";
return Function.apply(undefined, _toConsumableArray(argNames).concat([body])).apply(undefined, _toConsumableArray(args));
}
/**
* Create the `.accepts()` method for a list of fields.
*/
function createAccepts(fields) {
var argNames = ['$Address'].concat(_toConsumableArray(fields.map(function (_, index) {
return "type" + index;
})));
var args = [_symbols.$Address].concat(_toConsumableArray(fields.map(function (field) {
return field.type;
})));
var body = "\n \"use strict\";\n return function accepts (input) {\n if (input == null || typeof input !== 'object') {\n return false;\n }\n " + fields.map(function (_ref3, index) {
var name = _ref3.name;
var type = _ref3.type;
var offset = _ref3.offset;
return "\n if (!type" + index + ".accepts(input" + (isValidIdentifier(name) ? "." + name : "[" + JSON.stringify(name) + "]") + ")) {\n return false;\n }\n ";
}).join('') + "\n return true;\n };\n ";
return Function.apply(undefined, _toConsumableArray(argNames).concat([body])).apply(undefined, _toConsumableArray(args));
}
/**
* Create the `.toJSON()` method for a list of fields.
*/
function createToJSON(fields) {
return Function("\n \"use strict\";\n return {\n " + fields.map(function (_ref4) {
var name = _ref4.name;
if (isValidIdentifier(name)) {
return name + ": this." + name;
} else {
var sanitizedName = JSON.stringify(name);
return sanitizedName + ": this[" + sanitizedName + "]";
}
}).join(',\n ') + "\n };");
}
/**
* Create a function which can clear the given struct fields.
*/
function createClearStruct(fields) {
var clearable = fields.filter(function (_ref5) {
var type = _ref5.type;
return typeof type.clear === 'function';
});
var clearers = clearable.map(function (field) {
return field.type.clear;
});
var names = clearable.map(function (_, index) {
return "clear_" + index;
});
var body = "\n \"use strict\";\n return function clearStruct (backing, address) {\n " + names.map(function (name, index) {
return name + "(backing, address + " + clearable[index].offset + ");";
}).join('\n ') + "\n };\n ";
return Function.apply(undefined, _toConsumableArray(names).concat([body])).apply(undefined, _toConsumableArray(clearers));
}
/**
* Create a function which can destroy the given struct fields.
*/
function createStructDestructor(fields) {
var clearable = fields.filter(function (_ref6) {
var type = _ref6.type;
/* Issue 252 */
return type[_symbols.$CanContainReferences] && typeof type.clear === 'function';
});
var clearers = clearable.map(function (field) {
return field.type;
});
var names = clearable.map(function (_, index) {
return "clearable_" + index;
});
var body = "\n \"use strict\";\n return function destructor (backing, address) {\n " + names.map(function (name, index) {
return name + ".clear(backing, address + " + clearable[index].offset + ");";
}).join('\n ') + "\n };\n ";
return Function.apply(undefined, _toConsumableArray(names).concat([body])).apply(undefined, _toConsumableArray(clearers));
}
/**
* Create a function which can compare two structs by address.
*/
function createCompareAddresses(fields) {
var checkAddresses = fields.map(function (_ref7, index) {
var offset = _ref7.offset;
return "\n else if ((tmp = type" + index + ".compareAddresses(backing, a + " + offset + ", b + " + offset + ")) !== 0) {\n return tmp;\n }\n ";
}).join('');
var argNames = fields.map(function (_, index) {
return "type" + index;
});
var args = fields.map(function (_ref8) {
var type = _ref8.type;
return type;
});
var body = "\n \"use strict\";\n return function compareAddresses (backing, a, b) {\n var tmp;\n\n if (a === b) {\n return 0;\n }\n else if (a === 0) {\n return -1;\n }\n else if (b === 0) {\n return 1;\n }\n " + checkAddresses + "\n else {\n return 0;\n }\n };\n ";
return Function.apply(undefined, _toConsumableArray(argNames).concat([body])).apply(undefined, _toConsumableArray(args));
}
/**
* Create a function which can determine whether two structs are structurally equal.
*/
function createEqual(fields) {
var checkValues = fields.map(function (_ref9, index) {
var name = _ref9.name;
var type = _ref9.type;
if (typeof type.equal !== 'function') {
throw new Error("Type " + type.name + " does not have an equal() method.");
}
if (isValidIdentifier(name)) {
return "\n else if (!type" + index + ".equal(a." + name + ", b." + name + ")) {\n return false;\n }\n ";
} else {
var sanitizedName = JSON.stringify(name);
return "\n else if (!type" + index + ".equal(a[" + sanitizedName + "], b[" + sanitizedName + "])) {\n return false;\n }\n ";
}
}).join('');
var argNames = fields.map(function (_, index) {
return "type" + index;
});
var args = fields.map(function (_ref10) {
var type = _ref10.type;
return type;
});
var body = "\n \"use strict\";\n return function equal (a, b) {\n if (a === b) {\n return true;\n }\n else if (a == null || b == null) {\n return false;\n }\n " + checkValues + "\n else {\n return true;\n }\n };\n ";
return Function.apply(undefined, _toConsumableArray(argNames).concat([body])).apply(undefined, _toConsumableArray(args));
}
/**
* Create a function which can compare two struct instances.
*/
function createCompareValues(fields) {
var checkValues = fields.map(function (_ref11, index) {
var name = _ref11.name;
if (isValidIdentifier(name)) {
return "\n else if ((tmp = type" + index + ".compareValues(a." + name + ", b." + name + ")) !== 0) {\n return tmp;\n }\n ";
} else {
var sanitizedName = JSON.stringify(name);
return "\n else if ((tmp = type" + index + ".compareValues(a[" + sanitizedName + "], b[" + sanitizedName + "])) !== 0) {\n return tmp;\n }\n ";
}
}).join('');
var argNames = fields.map(function (_, index) {
return "type" + index;
});
var args = fields.map(function (_ref12) {
var type = _ref12.type;
return type;
});
var body = "\n \"use strict\";\n return function compareValues (a, b) {\n var tmp;\n if (a === b) {\n return 0;\n }\n else if (a == null) {\n return -1;\n }\n else if (b == null) {\n return 1;\n }\n " + checkValues + "\n else {\n return 0;\n }\n };\n ";
return Function.apply(undefined, _toConsumableArray(argNames).concat([body])).apply(undefined, _toConsumableArray(args));
}
/**
* Create a function which can compare a struct stored at a given address with a given value.
*/
function createCompareAddressValue(fields) {
var checkAddressValues = fields.map(function (_ref13, index) {
var name = _ref13.name;
var offset = _ref13.offset;
if (isValidIdentifier(name)) {
return "\n else if ((tmp = type" + index + ".compareAddressValue(backing, address + " + offset + ", value." + name + ")) !== 0) {\n return tmp;\n }\n ";
} else {
var sanitizedName = JSON.stringify(name);
return "\n else if ((tmp = type" + index + ".compareAddressValue(backing, address, value[" + sanitizedName + "])) !== 0) {\n return tmp;\n }\n ";
}
}).join('');
var argNames = fields.map(function (_, index) {
return "type" + index;
});
var args = fields.map(function (_ref14) {
var type = _ref14.type;
return type;
});
var body = "\n \"use strict\";\n return function compareAddressValue (backing, address, value) {\n var tmp;\n if (value == null || typeof value !== 'object') {\n return 1;\n }\n else if (value[$Address] === address) {\n return 0;\n }\n " + checkAddressValues + "\n else {\n return 0;\n }\n };\n ";
return Function.apply(undefined, ['$Address'].concat(_toConsumableArray(argNames), [body])).apply(undefined, [_symbols.$Address].concat(_toConsumableArray(args)));
}
/**
* Create a function which can hash structs with the given fields.
*/
function createHashStruct(fields) {
var checkValues = fields.map(function (_ref15, index) {
var name = _ref15.name;
var type = _ref15.type;
if (typeof type.hashValue !== 'function') {
throw new Error("Type " + type.name + " does not have a method called \"hashValue\".");
}
if (isValidIdentifier(name)) {
return "\n hash ^= type" + index + ".hashValue(input." + name + ");\n hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);\n ";
} else {
var sanitizedName = JSON.stringify(name);
return "\n hash ^= type" + index + ".hashValue(input[" + sanitizedName + "]);\n hash += (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);\n ";
}
}).join('');
var argNames = fields.map(function (_, index) {
return "type" + index;
});
var args = fields.map(function (_ref16) {
var type = _ref16.type;
return type;
});
var body = "\n \"use strict\";\n return function hashStruct (input) {\n var hash = 0x811c9dc5;\n\n " + checkValues + "\n\n return hash >>> 0;\n };\n ";
return Function.apply(undefined, _toConsumableArray(argNames).concat([body])).apply(undefined, _toConsumableArray(args));
}
/**
* Creates a function which can return random objects with the same shape as the struct.
*/
function createRandomValue(fields) {
var properties = fields.map(function (_ref17, index) {
var name = _ref17.name;
if (isValidIdentifier(name)) {
return " " + name + ": type" + index + ".randomValue()";
} else {
var sanitizedName = JSON.stringify(name);
return " " + sanitizedName + ": type" + index + ".randomValue()";
}
}).join(',\n');
var argNames = fields.map(function (_, index) {
return "type" + index;
});
var args = fields.map(function (_ref18) {
var type = _ref18.type;
return type;
});
var body = "\n \"use strict\";\n return function randomValue () {\n return new this({\n " + properties + "\n });\n };\n ";
return Function.apply(undefined, _toConsumableArray(argNames).concat([body])).apply(undefined, _toConsumableArray(args));
}
function isValidIdentifier(name) {
return (/^([A-Za-z_$])([A-Za-z_$0-9]*)$/.test(name)
);
}