UNPKG

capnp-js

Version:

Capnproto run-time decoding and encoding for Node

208 lines (204 loc) 7.97 kB
var meta = require('../../reader/list/meta'); var pointer = require('./pointer'); // Deep layout copying. /* * Copy a structure to a blob of memory. * * arena Arena - The source structure's arena. * layout StructureLayout - Stripped reader data describing the structure to * be copied. * targetArena BuilderArena - The arena where the copied structure will be * written. * blob Datum - The location within `targetArena` to begin writing the list. */ var setStruct = function(arena, layout, targetArena, blob) { var source = { segment: layout.segment, position: layout.dataSection }; // Copy the data section verbatim. var dataLength = layout.pointersSection - layout.dataSection; targetArena._write(source, dataLength, blob); // Deep copy the pointers section. source.position += dataLength; var p = { segment: blob.segment, position: blob.position + dataLength }; for (;source.position < layout.end; source.position += 8, p.position += 8) { pointer.setAnyPointer(arena, source, targetArena, p); } }; var setOrphanStruct = function(arena, layout) { var blob = arena._allocateOrphan(layout.end - layout.dataSection); setStruct(arena, layout, arena, blob); return { meta: 0, segment: blob.segment, dataSection: blob.position, pointersSection: blob.position + layout.pointersSection - layout.dataSection, end: blob.position + layout.end - layout.dataSection }; }; /* * Deep copy a list's pointers. The list's non-pointers remain untouched. * * arena Arena - The source list's arena. * layout ListLayout - Stripped reader data describing the list to be * copied. * targetArena BuilderArena - The arena where the copied list will be * written. * blob Datum - The location within `targetArena` to begin writing the list. * For inline composite lists, this should reference the position * immediately following the list's tag. */ var setListPointerSections = function(arena, layout, targetArena, blob) { var source = { segment: layout.segment, position: layout.begin }; var target = { segment: blob.segment, position: blob.position }; for (var i = 0; i < layout.length; ++i) { // Skip the data section. source.position += layout.dataBytes; target.position += layout.dataBytes; var end = source.position + layout.pointersBytes; // Copy the pointer section. for (;source.position < end; source.position += 8, target.position += 8) { pointer.setAnyPointer(arena, source, targetArena, target); } } }; /* * Copy the full list regardless of whether a particular item is a primitive * or a pointer. Any copied pointers will still reference with respect to * `layout.segment` within `arena`. * * arena Arena - The source list's arena. * meta ListMeta - Metadata describing the pointer to be copied. * layout ListLayout - Reader data describing the list to be copied. * targetArena BuilderArena - The arena where the copied list will be * written. * blob Datum - The location within `targetArena` to begin writing the list. * size UInt32 - The size of each list element in bytes. */ var setListVerbatim = function(arena, meta, layout, targetArena, blob) { var bytes; var source = { segment: layout.segment, position: layout.begin }; if (meta.layout === 1) { bytes = layout.length >>> 3; var remainder = layout.length & 7; if (remainder) { // Clobber any junk on the tail of the source in preparation for // copying. source.segment[source.position + bytes] &= 255 >>> 8 - remainder; bytes += 1; } } else { bytes = layout.length * (layout.dataBytes + layout.pointersBytes); } targetArena._write(source, bytes, blob); }; /* * Copy a list to a blob of memory. * * arena Arena - The source list's arena. * layout ListLayout - Stripped reader data describing the list to be * copied. * targetArena BuilderArena - The arena where the copied list will be * written. * blob Datum - The location within `targetArena` to begin writing the list. */ var setList = function(arena, layout, targetArena, blob) { var m = meta(layout); var data; if (m.layout === 7) { // Copy the tag word. targetArena._write({ segment: layout.segment, position: layout.begin - 8 }, 8, blob); data = { segment: blob.segment, position: blob.position + 8 }; } else { data = blob; } if (layout.dataBytes !== 0) setListVerbatim(arena, m, layout, targetArena, data); if (layout.pointersBytes !== 0) { /* * Overwrite verbatim pointer copies with deep copies. Since the * copying must succeed before linking into another data structure, * the parent data structure will not be corrupted upon failure. If * the data structure isn't copied subsequent to such a failure, * however, any garbage will leak. */ setListPointerSections(arena, layout, targetArena, data); } }; var setOrphanList = function(arena, layout) { var m = meta(layout); var blob, delta; if (m.layout === 7) { blob = arena._allocateOrphan(8 + layout.length * (layout.dataBytes + layout.pointersBytes)); delta = blob.position + 8 - layout.begin; } else if (m.layout === 1) { blob = arena._allocateOrphan((layout.length >>> 3) + (layout.length & 7 ? 1 : 0)); delta = blob.position - layout.begin; } else { blob = arena._allocateOrphan(layout.length * (layout.dataBytes + layout.pointersBytes)); delta = blob.position - layout.begin; } setList(arena, layout, arena, blob); return { meta: 1, segment: blob.segment, begin: layout.begin + delta, length: layout.length, dataBytes: layout.dataBytes, pointersBytes: layout.pointersBytes }; }; /* * Deep copy a reader's contents into an arena without setting any pointers * to it. * * * reader Reader - The reader whose data will be copied into the arena. * * arena BuilderArena - The arena that will incorporate the data of * `reader`. * * * RETURNS: Datum - The position of the incorporated data. */ var setAny = function(arena, layout, targetArena, blob) { switch (layout.meta) { case 0: setStruct(arena, layout, targetArena, blob); return; case 1: setList(arena, layout, targetArena, blob); return; default: throw new Error("Only structures and lists are supported"); } }; var setOrphanAny = function(arena, layout) { switch (layout.meta) { case 0: return setOrphanStruct(arena, layout); case 1: return setOrphanList(arena, layout); } }; exports.setStruct = setStruct; exports.setOrphanStruct = setOrphanStruct; exports.setList = setList; exports.setOrphanList = setOrphanList; exports.setAny = setAny; exports.setOrphanAny = setOrphanAny;