capnp-js
Version:
Capnproto run-time decoding and encoding for Node
120 lines (119 loc) • 4.8 kB
JavaScript
var type = require('../../type');
var copy = require('../copy/pointer');
var list = require('../layout/list');
var field = require('./field/index');
var statics = require('./statics');
var methods = require('./methods');
module.exports = function(Builder) {
var t = new type.List(Builder._TYPE);
var ct = Builder._LIST_CT;
var Structs = function(arena, isOrphan, layout) {
if (layout.dataBytes === null) {
throw new Error("Single bit structures are not supported");
}
this._arena = arena;
this._isOrphan = isOrphan;
this._segment = layout.segment;
this._begin = layout.begin;
this._length = layout.length;
this._dataBytes = layout.dataBytes;
this._pointersBytes = layout.pointersBytes;
this._stride = layout.dataBytes + layout.pointersBytes;
};
Structs._TYPE = t;
Structs._CT = ct;
Structs._FIELD = {};
Structs._HASH = "L|" + Builder._HASH;
statics.deref(Structs);
statics.set(Structs);
var stride = Structs._CT.dataBytes + Structs._CT.pointersBytes;
if (Structs._CT.layout === 7) {
Structs._init = function(arena, pointer, length) {
var blob = arena._preallocate(pointer.segment, 8 + length * stride);
arena._zero(blob, length * stride);
list.preallocated(pointer, blob, Structs._CT, length);
return Structs._deref(arena, pointer);
};
Structs._initOrphan = function(arena, length) {
var blob = arena._allocate(8 + length * stride);
/*
* Final word nulled by allocation (avoiding an unnecessary
* `+8`).
*/
arena._zero(blob, length * stride);
return new Structs(arena, true, {
segment: blob.segment,
begin: 8 + blob.position,
length: length,
dataBytes: ct.dataBytes,
pointersBytes: ct.pointersBytes
});
};
} else if (Structs._CT.layout === 1) {
throw new Error("Single bit structures are not supported");
} else {
statics.init(Structs);
statics.initOrphan(Structs);
}
field.install(Structs);
Structs.prototype = {
_TYPE: t,
_CT: ct,
_rt: methods.rt,
_layout: methods.layout
};
methods.install(Structs.prototype);
Structs.prototype.get = function(index) {
if (index < 0 || this._length <= index) {
throw new RangeError();
}
var position = this._begin + index * this._stride;
var pointers = position + this._dataBytes;
return new Builder(this._arena, false, {
meta: 0,
segment: this._segment,
dataSection: position,
pointersSection: pointers,
end: pointers + this._pointersBytes
});
};
Structs.prototype.setWithCaveats = function(index, instance) {
if (Builder._TYPE !== instance._TYPE) {
throw new TypeError();
}
var source = {
segment: instance._segment,
position: instance._dataSection
};
var target = {
segment: this._segment,
position: this._begin + index * this._stride
};
this._arena._write(source, this._dataBytes, target);
var bytes = instance._pointersSection - instance._dataSection;
var tail = this._dataBytes - bytes;
if (tail > 0) {
// Earlier version, so fill excess space with zeros.
target.position += bytes;
this.arena._zero(target, tail);
target.position += tail;
} else {
// This or later version.
target.position += this._dataBytes;
}
source.position += bytes;
bytes = instance._end - instance._pointersSection;
tail = this._pointersBytes - bytes;
bytes = Math.min(this._pointersBytes, bytes);
for (var i = 0; i < bytes; i += 8) {
copy.any(instance._arena, source, this._arena, target);
source.position += 8;
target.position += 8;
}
if (tail > 0) {
// Earlier version, so fill excess space with zeros.
this.arena._zero(target, tail);
}
};
return Structs;
};