Skip to content

Commit

Permalink
Implement serialization of an array of objects.
Browse files Browse the repository at this point in the history
Closes #333.
  • Loading branch information
flatheadmill committed Aug 5, 2015
1 parent a5a53ab commit afb26ac
Show file tree
Hide file tree
Showing 8 changed files with 255 additions and 45 deletions.
16 changes: 16 additions & 0 deletions compose/explode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
function explode (field) {
var little = field.endianness === 'l'
var bytes = field.bits / 8
return {
endianness: field.endianess,
type: 'integer',
little: little,
bite: little ? 0 : bytes - 1,
direction: little ? 1 : -1,
stop: little ? bytes : -1,
bits: field.bits,
bytes: bytes
}
}

module.exports = explode
46 changes: 4 additions & 42 deletions compose/parser/all.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
var Variables = require('../variables')
var explode = require('../explode')
var qualify = require('../qualify')
var $ = require('programmatic')

function Variables () {
this._variables = []
}

function qualify (name, depth) {
return name + (depth ? depth : '')
}

function integer (field, assignee) {
var read = [], bite = field.bite, stop = field.stop
while (bite != stop) {
Expand All @@ -26,35 +21,6 @@ function integer (field, assignee) {
', read, '')
}

function explode (field) {
var little = field.endianness === 'l'
var bytes = field.bits / 8
return {
endianness: field.endianness,
type: 'integer',
little: little,
bite: little ? 0 : bytes - 1,
direction: little ? 1 : -1,
stop: little ? bytes : -1,
bits: field.bits,
bytes: bytes
}
}


Variables.prototype.hoist = function (variable) {
if (this._variables.indexOf(variable) === -1) {
this._variables.push(variable)
this._variables.sort()
}
}

Variables.prototype.toString = function () {
return this._variables.map(function (variable) {
return 'var ' + variable
}).join('\n')
}

function constructor (variables, definition, depth) {
var fields = [], object = qualify('object', depth)
variables.hoist(object)
Expand Down Expand Up @@ -162,10 +128,8 @@ function parser (name, definition) {
}

module.exports = function (compiler, definition) {
var variables = new Variables
variables.hoist('parsers')
var source = $(' \n\
parsers = {} \n\
var parsers = {} \n\
')
Object.keys(definition).forEach(function (packet) {
source = $(' \n\
Expand All @@ -175,8 +139,6 @@ module.exports = function (compiler, definition) {
')
})
source = $(' \n\
', variables.toString(), ' \n\
// __blank__ \n\
', source, ' \n\
// __blank__ \n\
return parsers \n\
Expand Down
5 changes: 5 additions & 0 deletions compose/qualify.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function qualify (name, depth) {
return name + (depth ? depth : '')
}

module.exports = qualify
129 changes: 129 additions & 0 deletions compose/serializer/all.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
var Variables = require('../variables')
var explode = require('../explode')
var qualify = require('../qualify')
var $ = require('programmatic')

function integer (field, value) {
var bites = [], bite = field.bite, stop = field.stop, shift
while (bite != stop) {
shift = bite ? value + ' >>> ' + bite * 8 : value
bites.push('buffer[start++] = ' + shift + ' & 0xff')
bite += field.direction
}
return bites.join('\n')
}

function nested (variables, definition, depth) {
return $(' \n\
', serialize(variables, definition, depth), ' \n\
')
}

function lengthEncoded (variables, name, field, depth) {
var source = ''
var object = qualify('object', depth)
var length = qualify('length', depth)
var array = qualify('array', depth)
var subObject = qualify('object', depth + 1)
var i = qualify('i', depth)
variables.hoist(i)
variables.hoist(length)
variables.hoist(array)
variables.hoist(subObject)
var looped = nested(variables, field, depth + 1)
source = $(' \n\
' + array + ' = ' + object + '.' + name + ' \n\
' + length + ' = array.length \n\
// __blank__ \n\
', integer(explode(field.$length), length), ' \n\
// __blank__ \n\
for (' + i + ' = 0; ' + i + ' < length; ' + i + '++) { \n\
' + subObject + ' = array[' + i + '] \n\
', looped, ' \n\
} \n\
')
return source
}

function serialize (variables, definition, depth) {
var sources = []
for (var name in definition) {
if (name[0] === '$') {
continue
}
var field = definition[name]
if (Array.isArray(field)) {
field = field[0]
if (field.$length) {
sources.push(lengthEncoded(variables, name, field, depth))
}
} else {
var object = qualify('object', depth)
field = explode(field)
if (field.type === 'integer') {
sources.push($(' \n\
', integer(field, object + '.' + name), ' \n\
// __reference__ \n\
'))
}
}
}
return joinSources(sources)
}

function joinSources (sources) {
var source = sources[0]
for (var i = 1, I = sources.length; i < I; i++) {
source = $(' \n\
', source, ' \n\
// __blank__ \n\
', sources[i], ' \n\
')
}
return source
}

function serializer (name, definition) {
var variables = new Variables
var source = $(' \n\
', serialize(variables, definition, 0), ' \n\
')
return $(' \n\
serializers.' + name + ' = function () { \n\
} \n\
// __blank__ \n\
serializers.' + name + '.prototype.serialize = function (engine) { \n\
var buffer = engine.buffer \n\
var start = engine.start \n\
var end = engine.end \n\
var object = engine.object \n\
// __blank__ \n\
', String(variables), ' \n\
// __blank__ \n\
', source, ' \n\
// __blank__ \n\
engine.start = start \n\
// __blank__ \n\
return object \n\
} \n\
')
}

module.exports = function (compiler, definition) {
var source = $(' \n\
var serializers = {} \n\
')
Object.keys(definition).forEach(function (packet) {
source = $(' \n\
', source, ' \n\
// __blank__ \n\
', serializer(packet, definition[packet]), ' \n\
')
})
source = $(' \n\
', source, ' \n\
// __blank__ \n\
return serializers \n\
')
return compiler(source)
}
18 changes: 18 additions & 0 deletions compose/variables.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
function Variables () {
this._variables = []
}

Variables.prototype.hoist = function (variable) {
if (this._variables.indexOf(variable) === -1) {
this._variables.push(variable)
this._variables.sort()
}
}

Variables.prototype.toString = function () {
return this._variables.map(function (variable) {
return 'var ' + variable
}).join('\n')
}

module.exports = Variables
4 changes: 1 addition & 3 deletions t/generated/array-of-objects.parse.all.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
module.exports = (function () {
var parsers

parsers = {}
var parsers = {}

parsers.object = function () {
}
Expand Down
39 changes: 39 additions & 0 deletions t/generated/array-of-objects.serialize.all.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module.exports = (function () {
var serializers = {}

serializers.object = function () {
}

serializers.object.prototype.serialize = function (engine) {
var buffer = engine.buffer
var start = engine.start
var end = engine.end
var object = engine.object

var array
var i
var length
var object1

array = object.values
length = array.length

buffer[start++] = length >>> 8 & 0xff
buffer[start++] = length & 0xff

for (i = 0; i < length; i++) {
object1 = array[i]
buffer[start++] = object1.key >>> 8 & 0xff
buffer[start++] = object1.key & 0xff

buffer[start++] = object1.value >>> 8 & 0xff
buffer[start++] = object1.value & 0xff
}

engine.start = start

return object
}

return serializers
})()
43 changes: 43 additions & 0 deletions t/serialize/all/array-of-objects.t.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
require('proof')(2, prove)

function prove (assert) {
var path = require('path')
var compiler = require('../../../compiler/require')
var composer = require('../../../compose/serializer/all.js')
var filename = path.resolve(__filename, '../../../generated/array-of-objects.serialize.all.js')

var serializers = composer(compiler(filename), {
object: {
values: [{
$length: {
endianess: 'b',
bits: 16
},
key: {
endianess: 'b',
bits: 16
},
value: {
endianess: 'b',
bits: 16
}
}]
}
})
var buffer = new Buffer(10)
var object = {
values: [ { key: 2570, value: 1 }, { key: 2, value: 3 } ]
}
var engine = {
buffer: buffer,
start: 0,
end: buffer.length,
object: object
}
var serializer = new serializers.object
serializer.serialize(engine)
assert(engine.buffer.toJSON() , [
0x0, 0x2, 0xa, 0xa, 0x0, 0x1, 0x0, 0x2, 0x0, 0x3
], 'compiled')
assert(engine.start, buffer.length, 'start moved')
}

0 comments on commit afb26ac

Please sign in to comment.