From 4e87195739f2a5d9a05451b48773c8afdc680765 Mon Sep 17 00:00:00 2001 From: akiyamn Date: Sun, 24 Sep 2023 23:22:21 +1000 Subject: Initial commit (by create-cloudflare CLI) --- .../capnp-ts/src/serialization/pointers/struct.js | 839 +++++++++++++++++++++ 1 file changed, 839 insertions(+) create mode 100644 node_modules/capnp-ts/src/serialization/pointers/struct.js (limited to 'node_modules/capnp-ts/src/serialization/pointers/struct.js') diff --git a/node_modules/capnp-ts/src/serialization/pointers/struct.js b/node_modules/capnp-ts/src/serialization/pointers/struct.js new file mode 100644 index 0000000..bc14e52 --- /dev/null +++ b/node_modules/capnp-ts/src/serialization/pointers/struct.js @@ -0,0 +1,839 @@ +"use strict"; +/** + * @author jdiaz5513 + */ +Object.defineProperty(exports, "__esModule", { value: true }); +exports.checkPointerBounds = exports.checkDataBounds = exports.testWhich = exports.setVoid = exports.setUint8 = exports.setUint64 = exports.setUint32 = exports.setUint16 = exports.setText = exports.setPointer = exports.setInt8 = exports.setInt64 = exports.setInt32 = exports.setInt16 = exports.setFloat64 = exports.setFloat32 = exports.setBit = exports.initList = exports.initData = exports.getVoid = exports.getUint8 = exports.getUint64 = exports.getUint32 = exports.getUint16 = exports.getText = exports.getStruct = exports.getSize = exports.getPointerSection = exports.getPointerAs = exports.getPointer = exports.getList = exports.getInt8 = exports.getInt64 = exports.getInt32 = exports.getInt16 = exports.getFloat64 = exports.getFloat32 = exports.getDataSection = exports.getData = exports.getBit = exports.getAs = exports.disown = exports.adopt = exports.resize = exports.initStructAt = exports.initStruct = exports.Struct = void 0; +const tslib_1 = require("tslib"); +const debug_1 = tslib_1.__importDefault(require("debug")); +const constants_1 = require("../../constants"); +const index_1 = require("../../types/index"); +const util_1 = require("../../util"); +const list_element_size_1 = require("../list-element-size"); +const object_size_1 = require("../object-size"); +const data_1 = require("./data"); +const list_1 = require("./list"); +const pointer_1 = require("./pointer"); +const pointer_type_1 = require("./pointer-type"); +const text_1 = require("./text"); +const errors_1 = require("../../errors"); +const trace = debug_1.default("capnp:struct"); +trace("load"); +// Used to apply bit masks (default values). +const TMP_WORD = new DataView(new ArrayBuffer(8)); +class Struct extends pointer_1.Pointer { + /** + * Create a new pointer to a struct. + * + * @constructor {Struct} + * @param {Segment} segment The segment the pointer resides in. + * @param {number} byteOffset The offset from the beginning of the segment to the beginning of the pointer data. + * @param {any} [depthLimit=MAX_DEPTH] The nesting depth limit for this object. + * @param {number} [compositeIndex] If set, then this pointer is actually a reference to a composite list + * (`this._getPointerTargetType() === PointerType.LIST`), and this number is used as the index of the struct within + * the list. It is not valid to call `initStruct()` on a composite struct – the struct contents are initialized when + * the list pointer is initialized. + */ + constructor(segment, byteOffset, depthLimit = constants_1.MAX_DEPTH, compositeIndex) { + super(segment, byteOffset, depthLimit); + this._capnp.compositeIndex = compositeIndex; + this._capnp.compositeList = compositeIndex !== undefined; + } + static toString() { + return this._capnp.displayName; + } + toString() { + return (`Struct_${super.toString()}` + + `${this._capnp.compositeIndex === undefined ? "" : `,ci:${this._capnp.compositeIndex}`}`); + } +} +exports.Struct = Struct; +Struct._capnp = { + displayName: "Struct", +}; +Struct.getAs = getAs; +Struct.getBit = getBit; +Struct.getData = getData; +Struct.getFloat32 = getFloat32; +Struct.getFloat64 = getFloat64; +Struct.getUint8 = getUint8; +Struct.getUint16 = getUint16; +Struct.getUint32 = getUint32; +Struct.getUint64 = getUint64; +Struct.getInt8 = getInt8; +Struct.getInt16 = getInt16; +Struct.getInt32 = getInt32; +Struct.getInt64 = getInt64; +Struct.getList = getList; +Struct.getPointer = getPointer; +Struct.getPointerAs = getPointerAs; +Struct.getStruct = getStruct; +Struct.getText = getText; +Struct.initData = initData; +Struct.initList = initList; +Struct.initStruct = initStruct; +Struct.initStructAt = initStructAt; +Struct.setBit = setBit; +Struct.setFloat32 = setFloat32; +Struct.setFloat64 = setFloat64; +Struct.setUint8 = setUint8; +Struct.setUint16 = setUint16; +Struct.setUint32 = setUint32; +Struct.setUint64 = setUint64; +Struct.setInt8 = setInt8; +Struct.setInt16 = setInt16; +Struct.setInt32 = setInt32; +Struct.setInt64 = setInt64; +Struct.setText = setText; +Struct.testWhich = testWhich; +/** + * Initialize a struct with the provided object size. This will allocate new space for the struct contents, ideally in + * the same segment as this pointer. + * + * @param {ObjectSize} size An object describing the size of the struct's data and pointer sections. + * @param {Struct} s The struct to initialize. + * @returns {void} + */ +function initStruct(size, s) { + if (s._capnp.compositeIndex !== undefined) { + throw new Error(util_1.format(errors_1.PTR_INIT_COMPOSITE_STRUCT, s)); + } + // Make sure to clear existing contents before overwriting the pointer data (erase is a noop if already empty). + pointer_1.erase(s); + const c = s.segment.allocate(object_size_1.getByteLength(size)); + const res = pointer_1.initPointer(c.segment, c.byteOffset, s); + pointer_1.setStructPointer(res.offsetWords, size, res.pointer); +} +exports.initStruct = initStruct; +function initStructAt(index, StructClass, p) { + const s = getPointerAs(index, StructClass, p); + initStruct(StructClass._capnp.size, s); + return s; +} +exports.initStructAt = initStructAt; +/** + * Make a shallow copy of a struct's contents and update the pointer to point to the new content. The data and pointer + * sections will be resized to the provided size. + * + * WARNING: This method can cause data loss if `dstSize` is smaller than the original size! + * + * @param {ObjectSize} dstSize The desired size for the struct contents. + * @param {Struct} s The struct to resize. + * @returns {void} + */ +function resize(dstSize, s) { + const srcSize = getSize(s); + const srcContent = pointer_1.getContent(s); + const dstContent = s.segment.allocate(object_size_1.getByteLength(dstSize)); + // Only copy the data section for now. The pointer section will need to be rewritten. + dstContent.segment.copyWords(dstContent.byteOffset, srcContent.segment, srcContent.byteOffset, Math.min(object_size_1.getDataWordLength(srcSize), object_size_1.getDataWordLength(dstSize))); + const res = pointer_1.initPointer(dstContent.segment, dstContent.byteOffset, s); + pointer_1.setStructPointer(res.offsetWords, dstSize, res.pointer); + // Iterate through the new pointer section and update the offsets so they point to the right place. This is a bit + // more complicated than it appears due to the fact that the original pointers could have been far pointers, and + // the new pointers might need to be allocated as far pointers if the segment is full. + for (let i = 0; i < Math.min(srcSize.pointerLength, dstSize.pointerLength); i++) { + const srcPtr = new pointer_1.Pointer(srcContent.segment, srcContent.byteOffset + srcSize.dataByteLength + i * 8); + if (pointer_1.isNull(srcPtr)) { + // If source pointer is null, leave the destination pointer as default null. + continue; + } + const srcPtrTarget = pointer_1.followFars(srcPtr); + const srcPtrContent = pointer_1.getContent(srcPtr); + const dstPtr = new pointer_1.Pointer(dstContent.segment, dstContent.byteOffset + dstSize.dataByteLength + i * 8); + // For composite lists the offset needs to point to the tag word, not the first element which is what getContent + // returns. + if (pointer_1.getTargetPointerType(srcPtr) === pointer_type_1.PointerType.LIST && + pointer_1.getTargetListElementSize(srcPtr) === list_element_size_1.ListElementSize.COMPOSITE) { + srcPtrContent.byteOffset -= 8; + } + const r = pointer_1.initPointer(srcPtrContent.segment, srcPtrContent.byteOffset, dstPtr); + // Read the old pointer data, but discard the original offset. + const a = srcPtrTarget.segment.getUint8(srcPtrTarget.byteOffset) & 0x03; + const b = srcPtrTarget.segment.getUint32(srcPtrTarget.byteOffset + 4); + r.pointer.segment.setUint32(r.pointer.byteOffset, a | (r.offsetWords << 2)); + r.pointer.segment.setUint32(r.pointer.byteOffset + 4, b); + } + // Zero out the old data and pointer sections. + srcContent.segment.fillZeroWords(srcContent.byteOffset, object_size_1.getWordLength(srcSize)); +} +exports.resize = resize; +function adopt(src, s) { + if (s._capnp.compositeIndex !== undefined) { + throw new Error(util_1.format(errors_1.PTR_ADOPT_COMPOSITE_STRUCT, s)); + } + pointer_1.Pointer.adopt(src, s); +} +exports.adopt = adopt; +function disown(s) { + if (s._capnp.compositeIndex !== undefined) { + throw new Error(util_1.format(errors_1.PTR_DISOWN_COMPOSITE_STRUCT, s)); + } + return pointer_1.Pointer.disown(s); +} +exports.disown = disown; +/** + * Convert a struct to a struct of the provided class. Particularly useful when casting to nested group types. + * + * @protected + * @template T + * @param {StructCtor} StructClass The struct class to convert to. Not particularly useful if `Struct`. + * @param {Struct} s The struct to convert. + * @returns {T} A new instance of the desired struct class pointing to the same location. + */ +function getAs(StructClass, s) { + return new StructClass(s.segment, s.byteOffset, s._capnp.depthLimit, s._capnp.compositeIndex); +} +exports.getAs = getAs; +/** + * Read a boolean (bit) value out of a struct. + * + * @protected + * @param {number} bitOffset The offset in **bits** from the start of the data section. + * @param {Struct} s The struct to read from. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {boolean} The value. + */ +function getBit(bitOffset, s, defaultMask) { + const byteOffset = Math.floor(bitOffset / 8); + const bitMask = 1 << bitOffset % 8; + checkDataBounds(byteOffset, 1, s); + const ds = getDataSection(s); + const v = ds.segment.getUint8(ds.byteOffset + byteOffset); + if (defaultMask === undefined) + return (v & bitMask) !== 0; + const defaultValue = defaultMask.getUint8(0); + return ((v ^ defaultValue) & bitMask) !== 0; +} +exports.getBit = getBit; +function getData(index, s, defaultValue) { + checkPointerBounds(index, s); + const ps = getPointerSection(s); + ps.byteOffset += index * 8; + const l = new data_1.Data(ps.segment, ps.byteOffset, s._capnp.depthLimit - 1); + if (pointer_1.isNull(l)) { + if (defaultValue) { + pointer_1.Pointer.copyFrom(defaultValue, l); + } + else { + list_1.List.initList(list_element_size_1.ListElementSize.BYTE, 0, l); + } + } + return l; +} +exports.getData = getData; +function getDataSection(s) { + return pointer_1.getContent(s); +} +exports.getDataSection = getDataSection; +/** + * Read a float32 value out of a struct. + * + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {Struct} s The struct to read from. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {number} The value. + */ +function getFloat32(byteOffset, s, defaultMask) { + checkDataBounds(byteOffset, 4, s); + const ds = getDataSection(s); + if (defaultMask === undefined) { + return ds.segment.getFloat32(ds.byteOffset + byteOffset); + } + const v = ds.segment.getUint32(ds.byteOffset + byteOffset) ^ defaultMask.getUint32(0, true); + TMP_WORD.setUint32(0, v, constants_1.NATIVE_LITTLE_ENDIAN); + return TMP_WORD.getFloat32(0, constants_1.NATIVE_LITTLE_ENDIAN); +} +exports.getFloat32 = getFloat32; +/** + * Read a float64 value out of this segment. + * + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {Struct} s The struct to read from. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {number} The value. + */ +function getFloat64(byteOffset, s, defaultMask) { + checkDataBounds(byteOffset, 8, s); + const ds = getDataSection(s); + if (defaultMask !== undefined) { + const lo = ds.segment.getUint32(ds.byteOffset + byteOffset) ^ defaultMask.getUint32(0, true); + const hi = ds.segment.getUint32(ds.byteOffset + byteOffset + 4) ^ defaultMask.getUint32(4, true); + TMP_WORD.setUint32(0, lo, constants_1.NATIVE_LITTLE_ENDIAN); + TMP_WORD.setUint32(4, hi, constants_1.NATIVE_LITTLE_ENDIAN); + return TMP_WORD.getFloat64(0, constants_1.NATIVE_LITTLE_ENDIAN); + } + return ds.segment.getFloat64(ds.byteOffset + byteOffset); +} +exports.getFloat64 = getFloat64; +/** + * Read an int16 value out of this segment. + * + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {Struct} s The struct to read from. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {number} The value. + */ +function getInt16(byteOffset, s, defaultMask) { + checkDataBounds(byteOffset, 2, s); + const ds = getDataSection(s); + if (defaultMask === undefined) { + return ds.segment.getInt16(ds.byteOffset + byteOffset); + } + const v = ds.segment.getUint16(ds.byteOffset + byteOffset) ^ defaultMask.getUint16(0, true); + TMP_WORD.setUint16(0, v, constants_1.NATIVE_LITTLE_ENDIAN); + return TMP_WORD.getInt16(0, constants_1.NATIVE_LITTLE_ENDIAN); +} +exports.getInt16 = getInt16; +/** + * Read an int32 value out of this segment. + * + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {Struct} s The struct to read from. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {number} The value. + */ +function getInt32(byteOffset, s, defaultMask) { + checkDataBounds(byteOffset, 4, s); + const ds = getDataSection(s); + if (defaultMask === undefined) { + return ds.segment.getInt32(ds.byteOffset + byteOffset); + } + const v = ds.segment.getUint32(ds.byteOffset + byteOffset) ^ defaultMask.getUint16(0, true); + TMP_WORD.setUint32(0, v, constants_1.NATIVE_LITTLE_ENDIAN); + return TMP_WORD.getInt32(0, constants_1.NATIVE_LITTLE_ENDIAN); +} +exports.getInt32 = getInt32; +/** + * Read an int64 value out of this segment. + * + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {Struct} s The struct to read from. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {number} The value. + */ +function getInt64(byteOffset, s, defaultMask) { + checkDataBounds(byteOffset, 8, s); + const ds = getDataSection(s); + if (defaultMask === undefined) { + return ds.segment.getInt64(ds.byteOffset + byteOffset); + } + const lo = ds.segment.getUint32(ds.byteOffset + byteOffset) ^ defaultMask.getUint32(0, true); + const hi = ds.segment.getUint32(ds.byteOffset + byteOffset + 4) ^ defaultMask.getUint32(4, true); + TMP_WORD.setUint32(0, lo, constants_1.NATIVE_LITTLE_ENDIAN); + TMP_WORD.setUint32(4, hi, constants_1.NATIVE_LITTLE_ENDIAN); + return new index_1.Int64(new Uint8Array(TMP_WORD.buffer.slice(0))); +} +exports.getInt64 = getInt64; +/** + * Read an int8 value out of this segment. + * + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {Struct} s The struct to read from. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {number} The value. + */ +function getInt8(byteOffset, s, defaultMask) { + checkDataBounds(byteOffset, 1, s); + const ds = getDataSection(s); + if (defaultMask === undefined) { + return ds.segment.getInt8(ds.byteOffset + byteOffset); + } + const v = ds.segment.getUint8(ds.byteOffset + byteOffset) ^ defaultMask.getUint8(0); + TMP_WORD.setUint8(0, v); + return TMP_WORD.getInt8(0); +} +exports.getInt8 = getInt8; +function getList(index, ListClass, s, defaultValue) { + checkPointerBounds(index, s); + const ps = getPointerSection(s); + ps.byteOffset += index * 8; + const l = new ListClass(ps.segment, ps.byteOffset, s._capnp.depthLimit - 1); + if (pointer_1.isNull(l)) { + if (defaultValue) { + pointer_1.Pointer.copyFrom(defaultValue, l); + } + else { + list_1.List.initList(ListClass._capnp.size, 0, l, ListClass._capnp.compositeSize); + } + } + else if (ListClass._capnp.compositeSize !== undefined) { + // If this is a composite list we need to be sure the composite elements are big enough to hold everything as + // specified in the schema. If the new schema has added fields we'll need to "resize" (shallow-copy) the list so + // it has room for the new fields. + const srcSize = pointer_1.getTargetCompositeListSize(l); + const dstSize = ListClass._capnp.compositeSize; + if (dstSize.dataByteLength > srcSize.dataByteLength || dstSize.pointerLength > srcSize.pointerLength) { + const srcContent = pointer_1.getContent(l); + const srcLength = pointer_1.getTargetListLength(l); + trace("resizing composite list %s due to protocol upgrade, new size: %d", l, object_size_1.getByteLength(dstSize) * srcLength); + // Allocate an extra 8 bytes for the tag. + const dstContent = l.segment.allocate(object_size_1.getByteLength(dstSize) * srcLength + 8); + const res = pointer_1.initPointer(dstContent.segment, dstContent.byteOffset, l); + pointer_1.setListPointer(res.offsetWords, ListClass._capnp.size, srcLength, res.pointer, dstSize); + // Write the new tag word. + pointer_1.setStructPointer(srcLength, dstSize, dstContent); + // Seek ahead past the tag word before copying the content. + dstContent.byteOffset += 8; + for (let i = 0; i < srcLength; i++) { + const srcElementOffset = srcContent.byteOffset + i * object_size_1.getByteLength(srcSize); + const dstElementOffset = dstContent.byteOffset + i * object_size_1.getByteLength(dstSize); + // Copy the data section. + dstContent.segment.copyWords(dstElementOffset, srcContent.segment, srcElementOffset, object_size_1.getWordLength(srcSize)); + // Iterate through the pointers and update the offsets so they point to the right place. + for (let j = 0; j < srcSize.pointerLength; j++) { + const srcPtr = new pointer_1.Pointer(srcContent.segment, srcElementOffset + srcSize.dataByteLength + j * 8); + const dstPtr = new pointer_1.Pointer(dstContent.segment, dstElementOffset + dstSize.dataByteLength + j * 8); + const srcPtrTarget = pointer_1.followFars(srcPtr); + const srcPtrContent = pointer_1.getContent(srcPtr); + if (pointer_1.getTargetPointerType(srcPtr) === pointer_type_1.PointerType.LIST && + pointer_1.getTargetListElementSize(srcPtr) === list_element_size_1.ListElementSize.COMPOSITE) { + srcPtrContent.byteOffset -= 8; + } + const r = pointer_1.initPointer(srcPtrContent.segment, srcPtrContent.byteOffset, dstPtr); + // Read the old pointer data, but discard the original offset. + const a = srcPtrTarget.segment.getUint8(srcPtrTarget.byteOffset) & 0x03; + const b = srcPtrTarget.segment.getUint32(srcPtrTarget.byteOffset + 4); + r.pointer.segment.setUint32(r.pointer.byteOffset, a | (r.offsetWords << 2)); + r.pointer.segment.setUint32(r.pointer.byteOffset + 4, b); + } + } + // Zero out the old content. + srcContent.segment.fillZeroWords(srcContent.byteOffset, object_size_1.getWordLength(srcSize) * srcLength); + } + } + return l; +} +exports.getList = getList; +function getPointer(index, s) { + checkPointerBounds(index, s); + const ps = getPointerSection(s); + ps.byteOffset += index * 8; + return new pointer_1.Pointer(ps.segment, ps.byteOffset, s._capnp.depthLimit - 1); +} +exports.getPointer = getPointer; +function getPointerAs(index, PointerClass, s) { + checkPointerBounds(index, s); + const ps = getPointerSection(s); + ps.byteOffset += index * 8; + return new PointerClass(ps.segment, ps.byteOffset, s._capnp.depthLimit - 1); +} +exports.getPointerAs = getPointerAs; +function getPointerSection(s) { + const ps = pointer_1.getContent(s); + ps.byteOffset += util_1.padToWord(getSize(s).dataByteLength); + return ps; +} +exports.getPointerSection = getPointerSection; +function getSize(s) { + if (s._capnp.compositeIndex !== undefined) { + // For composite lists the object size is stored in a tag word right before the content. + const c = pointer_1.getContent(s, true); + c.byteOffset -= 8; + return pointer_1.getStructSize(c); + } + return pointer_1.getTargetStructSize(s); +} +exports.getSize = getSize; +function getStruct(index, StructClass, s, defaultValue) { + const t = getPointerAs(index, StructClass, s); + if (pointer_1.isNull(t)) { + if (defaultValue) { + pointer_1.Pointer.copyFrom(defaultValue, t); + } + else { + initStruct(StructClass._capnp.size, t); + } + } + else { + pointer_1.validate(pointer_type_1.PointerType.STRUCT, t); + const ts = pointer_1.getTargetStructSize(t); + // This can happen when reading a struct that was constructed with an older version of the same schema, and new + // fields were added to the struct. A shallow copy of the struct will be made so that there's enough room for the + // data and pointer sections. This will unfortunately leave a "hole" of zeroes in the message, but that hole will + // at least compress well. + if (ts.dataByteLength < StructClass._capnp.size.dataByteLength || + ts.pointerLength < StructClass._capnp.size.pointerLength) { + trace("need to resize child struct %s", t); + resize(StructClass._capnp.size, t); + } + } + return t; +} +exports.getStruct = getStruct; +function getText(index, s, defaultValue) { + const t = text_1.Text.fromPointer(getPointer(index, s)); + // FIXME: This will perform an unnecessary string<>ArrayBuffer roundtrip. + if (pointer_1.isNull(t) && defaultValue) + t.set(0, defaultValue); + return t.get(0); +} +exports.getText = getText; +/** + * Read an uint16 value out of a struct.. + * + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {Struct} s The struct to read from. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {number} The value. + */ +function getUint16(byteOffset, s, defaultMask) { + checkDataBounds(byteOffset, 2, s); + const ds = getDataSection(s); + if (defaultMask === undefined) { + return ds.segment.getUint16(ds.byteOffset + byteOffset); + } + return ds.segment.getUint16(ds.byteOffset + byteOffset) ^ defaultMask.getUint16(0, true); +} +exports.getUint16 = getUint16; +/** + * Read an uint32 value out of a struct. + * + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {Struct} s The struct to read from. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {number} The value. + */ +function getUint32(byteOffset, s, defaultMask) { + checkDataBounds(byteOffset, 4, s); + const ds = getDataSection(s); + if (defaultMask === undefined) { + return ds.segment.getUint32(ds.byteOffset + byteOffset); + } + return ds.segment.getUint32(ds.byteOffset + byteOffset) ^ defaultMask.getUint32(0, true); +} +exports.getUint32 = getUint32; +/** + * Read an uint64 value out of a struct. + * + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {Struct} s The struct to read from. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {number} The value. + */ +function getUint64(byteOffset, s, defaultMask) { + checkDataBounds(byteOffset, 8, s); + const ds = getDataSection(s); + if (defaultMask === undefined) { + return ds.segment.getUint64(ds.byteOffset + byteOffset); + } + const lo = ds.segment.getUint32(ds.byteOffset + byteOffset) ^ defaultMask.getUint32(0, true); + const hi = ds.segment.getUint32(ds.byteOffset + byteOffset + 4) ^ defaultMask.getUint32(4, true); + TMP_WORD.setUint32(0, lo, constants_1.NATIVE_LITTLE_ENDIAN); + TMP_WORD.setUint32(4, hi, constants_1.NATIVE_LITTLE_ENDIAN); + return new index_1.Uint64(new Uint8Array(TMP_WORD.buffer.slice(0))); +} +exports.getUint64 = getUint64; +/** + * Read an uint8 value out of a struct. + * + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {Struct} s The struct to read from. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {number} The value. + */ +function getUint8(byteOffset, s, defaultMask) { + checkDataBounds(byteOffset, 1, s); + const ds = getDataSection(s); + if (defaultMask === undefined) { + return ds.segment.getUint8(ds.byteOffset + byteOffset); + } + return ds.segment.getUint8(ds.byteOffset + byteOffset) ^ defaultMask.getUint8(0); +} +exports.getUint8 = getUint8; +function getVoid() { + throw new Error(errors_1.INVARIANT_UNREACHABLE_CODE); +} +exports.getVoid = getVoid; +function initData(index, length, s) { + checkPointerBounds(index, s); + const ps = getPointerSection(s); + ps.byteOffset += index * 8; + const l = new data_1.Data(ps.segment, ps.byteOffset, s._capnp.depthLimit - 1); + pointer_1.erase(l); + list_1.List.initList(list_element_size_1.ListElementSize.BYTE, length, l); + return l; +} +exports.initData = initData; +function initList(index, ListClass, length, s) { + checkPointerBounds(index, s); + const ps = getPointerSection(s); + ps.byteOffset += index * 8; + const l = new ListClass(ps.segment, ps.byteOffset, s._capnp.depthLimit - 1); + pointer_1.erase(l); + list_1.List.initList(ListClass._capnp.size, length, l, ListClass._capnp.compositeSize); + return l; +} +exports.initList = initList; +/** + * Write a boolean (bit) value to the struct. + * + * @protected + * @param {number} bitOffset The offset in **bits** from the start of the data section. + * @param {boolean} value The value to write (writes a 0 for `false`, 1 for `true`). + * @param {Struct} s The struct to write to. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {void} + */ +function setBit(bitOffset, value, s, defaultMask) { + const byteOffset = Math.floor(bitOffset / 8); + const bitMask = 1 << bitOffset % 8; + checkDataBounds(byteOffset, 1, s); + const ds = getDataSection(s); + const b = ds.segment.getUint8(ds.byteOffset + byteOffset); + // If the default mask bit is set, that means `true` values are actually written as `0`. + if (defaultMask !== undefined) { + value = (defaultMask.getUint8(0) & bitMask) !== 0 ? !value : value; + } + ds.segment.setUint8(ds.byteOffset + byteOffset, value ? b | bitMask : b & ~bitMask); +} +exports.setBit = setBit; +/** + * Write a primitive float32 value to the struct. + * + * @protected + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {number} value The value to write. + * @param {Struct} s The struct to write to. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {void} + */ +function setFloat32(byteOffset, value, s, defaultMask) { + checkDataBounds(byteOffset, 4, s); + const ds = getDataSection(s); + if (defaultMask !== undefined) { + TMP_WORD.setFloat32(0, value, constants_1.NATIVE_LITTLE_ENDIAN); + const v = TMP_WORD.getUint32(0, constants_1.NATIVE_LITTLE_ENDIAN) ^ defaultMask.getUint32(0, true); + ds.segment.setUint32(ds.byteOffset + byteOffset, v); + return; + } + ds.segment.setFloat32(ds.byteOffset + byteOffset, value); +} +exports.setFloat32 = setFloat32; +/** + * Write a primitive float64 value to the struct. + * + * @protected + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {number} value The value to write. + * @param {Struct} s The struct to write to. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {void} + */ +function setFloat64(byteOffset, value, s, defaultMask) { + checkDataBounds(byteOffset, 8, s); + const ds = getDataSection(s); + if (defaultMask !== undefined) { + TMP_WORD.setFloat64(0, value, constants_1.NATIVE_LITTLE_ENDIAN); + const lo = TMP_WORD.getUint32(0, constants_1.NATIVE_LITTLE_ENDIAN) ^ defaultMask.getUint32(0, true); + const hi = TMP_WORD.getUint32(4, constants_1.NATIVE_LITTLE_ENDIAN) ^ defaultMask.getUint32(4, true); + ds.segment.setUint32(ds.byteOffset + byteOffset, lo); + ds.segment.setUint32(ds.byteOffset + byteOffset + 4, hi); + return; + } + ds.segment.setFloat64(ds.byteOffset + byteOffset, value); +} +exports.setFloat64 = setFloat64; +/** + * Write a primitive int16 value to the struct. + * + * @protected + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {number} value The value to write. + * @param {Struct} s The struct to write to. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {void} + */ +function setInt16(byteOffset, value, s, defaultMask) { + checkDataBounds(byteOffset, 2, s); + const ds = getDataSection(s); + if (defaultMask !== undefined) { + TMP_WORD.setInt16(0, value, constants_1.NATIVE_LITTLE_ENDIAN); + const v = TMP_WORD.getUint16(0, constants_1.NATIVE_LITTLE_ENDIAN) ^ defaultMask.getUint16(0, true); + ds.segment.setUint16(ds.byteOffset + byteOffset, v); + return; + } + ds.segment.setInt16(ds.byteOffset + byteOffset, value); +} +exports.setInt16 = setInt16; +/** + * Write a primitive int32 value to the struct. + * + * @protected + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {number} value The value to write. + * @param {Struct} s The struct to write to. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {void} + */ +function setInt32(byteOffset, value, s, defaultMask) { + checkDataBounds(byteOffset, 4, s); + const ds = getDataSection(s); + if (defaultMask !== undefined) { + TMP_WORD.setInt32(0, value, constants_1.NATIVE_LITTLE_ENDIAN); + const v = TMP_WORD.getUint32(0, constants_1.NATIVE_LITTLE_ENDIAN) ^ defaultMask.getUint32(0, true); + ds.segment.setUint32(ds.byteOffset + byteOffset, v); + return; + } + ds.segment.setInt32(ds.byteOffset + byteOffset, value); +} +exports.setInt32 = setInt32; +/** + * Write a primitive int64 value to the struct. + * + * @protected + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {number} value The value to write. + * @param {Struct} s The struct to write to. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {void} + */ +function setInt64(byteOffset, value, s, defaultMask) { + checkDataBounds(byteOffset, 8, s); + const ds = getDataSection(s); + if (defaultMask !== undefined) { + // PERF: We could cast the Int64 to a DataView to apply the mask using four 32-bit reads, but we already have a + // typed array so avoiding the object allocation turns out to be slightly faster. Int64 is guaranteed to be in + // little-endian format by design. + for (let i = 0; i < 8; i++) { + ds.segment.setUint8(ds.byteOffset + byteOffset + i, value.buffer[i] ^ defaultMask.getUint8(i)); + } + return; + } + ds.segment.setInt64(ds.byteOffset + byteOffset, value); +} +exports.setInt64 = setInt64; +/** + * Write a primitive int8 value to the struct. + * + * @protected + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {number} value The value to write. + * @param {Struct} s The struct to write to. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {void} + */ +function setInt8(byteOffset, value, s, defaultMask) { + checkDataBounds(byteOffset, 1, s); + const ds = getDataSection(s); + if (defaultMask !== undefined) { + TMP_WORD.setInt8(0, value); + const v = TMP_WORD.getUint8(0) ^ defaultMask.getUint8(0); + ds.segment.setUint8(ds.byteOffset + byteOffset, v); + return; + } + ds.segment.setInt8(ds.byteOffset + byteOffset, value); +} +exports.setInt8 = setInt8; +function setPointer(index, value, s) { + pointer_1.copyFrom(value, getPointer(index, s)); +} +exports.setPointer = setPointer; +function setText(index, value, s) { + text_1.Text.fromPointer(getPointer(index, s)).set(0, value); +} +exports.setText = setText; +/** + * Write a primitive uint16 value to the struct. + * + * @protected + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {number} value The value to write. + * @param {Struct} s The struct to write to. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {void} + */ +function setUint16(byteOffset, value, s, defaultMask) { + checkDataBounds(byteOffset, 2, s); + const ds = getDataSection(s); + if (defaultMask !== undefined) + value ^= defaultMask.getUint16(0, true); + ds.segment.setUint16(ds.byteOffset + byteOffset, value); +} +exports.setUint16 = setUint16; +/** + * Write a primitive uint32 value to the struct. + * + * @protected + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {number} value The value to write. + * @param {Struct} s The struct to write to. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {void} + */ +function setUint32(byteOffset, value, s, defaultMask) { + checkDataBounds(byteOffset, 4, s); + const ds = getDataSection(s); + if (defaultMask !== undefined) + value ^= defaultMask.getUint32(0, true); + ds.segment.setUint32(ds.byteOffset + byteOffset, value); +} +exports.setUint32 = setUint32; +/** + * Write a primitive uint64 value to the struct. + * + * @protected + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {number} value The value to write. + * @param {Struct} s The struct to write to. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {void} + */ +function setUint64(byteOffset, value, s, defaultMask) { + checkDataBounds(byteOffset, 8, s); + const ds = getDataSection(s); + if (defaultMask !== undefined) { + // PERF: We could cast the Uint64 to a DataView to apply the mask using four 32-bit reads, but we already have a + // typed array so avoiding the object allocation turns out to be slightly faster. Uint64 is guaranteed to be in + // little-endian format by design. + for (let i = 0; i < 8; i++) { + ds.segment.setUint8(ds.byteOffset + byteOffset + i, value.buffer[i] ^ defaultMask.getUint8(i)); + } + return; + } + ds.segment.setUint64(ds.byteOffset + byteOffset, value); +} +exports.setUint64 = setUint64; +/** + * Write a primitive uint8 value to the struct. + * + * @protected + * @param {number} byteOffset The offset in bytes from the start of the data section. + * @param {number} value The value to write. + * @param {Struct} s The struct to write to. + * @param {DataView} [defaultMask] The default value as a DataView. + * @returns {void} + */ +function setUint8(byteOffset, value, s, defaultMask) { + checkDataBounds(byteOffset, 1, s); + const ds = getDataSection(s); + if (defaultMask !== undefined) + value ^= defaultMask.getUint8(0); + ds.segment.setUint8(ds.byteOffset + byteOffset, value); +} +exports.setUint8 = setUint8; +function setVoid() { + throw new Error(errors_1.INVARIANT_UNREACHABLE_CODE); +} +exports.setVoid = setVoid; +function testWhich(name, found, wanted, s) { + if (found !== wanted) { + throw new Error(util_1.format(errors_1.PTR_INVALID_UNION_ACCESS, s, name, found, wanted)); + } +} +exports.testWhich = testWhich; +function checkDataBounds(byteOffset, byteLength, s) { + const dataByteLength = getSize(s).dataByteLength; + if (byteOffset < 0 || byteLength < 0 || byteOffset + byteLength > dataByteLength) { + throw new Error(util_1.format(errors_1.PTR_STRUCT_DATA_OUT_OF_BOUNDS, s, byteLength, byteOffset, dataByteLength)); + } +} +exports.checkDataBounds = checkDataBounds; +function checkPointerBounds(index, s) { + const pointerLength = getSize(s).pointerLength; + if (index < 0 || index >= pointerLength) { + throw new Error(util_1.format(errors_1.PTR_STRUCT_POINTER_OUT_OF_BOUNDS, s, index, pointerLength)); + } +} +exports.checkPointerBounds = checkPointerBounds; +//# sourceMappingURL=struct.js.map \ No newline at end of file -- cgit v1.2.3