utils = require './utils' class Struct constructor: (@fields = {}) -> decode: (stream, parent, length = 0) -> res = @_setup stream, parent, length @_parseFields stream, res, @fields @process?.call(res, stream) return res _setup: (stream, parent, length) -> res = {} # define hidden properties Object.defineProperties res, parent: { value: parent } _startOffset: { value: stream.pos } _currentOffset: { value: 0, writable: true } _length: { value: length } return res _parseFields: (stream, res, fields) -> for key, type of fields if typeof type is 'function' val = type.call(res, res) else val = type.decode(stream, res) unless val is undefined if val instanceof utils.PropertyDescriptor Object.defineProperty res, key, val else res[key] = val res._currentOffset = stream.pos - res._startOffset return size: (val = {}, parent, includePointers = true) -> ctx = parent: parent val: val pointerSize: 0 size = 0 for key, type of @fields when type.size? size += type.size(val[key], ctx) if includePointers size += ctx.pointerSize return size encode: (stream, val, parent) -> @preEncode?.call(val, stream) ctx = pointers: [] startOffset: stream.pos parent: parent val: val pointerSize: 0 ctx.pointerOffset = stream.pos + @size(val, ctx, false) for key, type of @fields when type.encode? type.encode(stream, val[key], ctx) i = 0 while i < ctx.pointers.length ptr = ctx.pointers[i++] ptr.type.encode(stream, ptr.val, ptr.parent) return module.exports = Struct