protodef
Version:
A simple yet powerful way to define binary protocols
72 lines (64 loc) • 3.34 kB
JavaScript
const { getField, getFieldInfo, tryDoc, PartialReadError } = require('../utils')
module.exports = {
switch: [readSwitch, writeSwitch, sizeOfSwitch, require('../../ProtoDef/schemas/conditional.json').switch],
option: [readOption, writeOption, sizeOfOption, require('../../ProtoDef/schemas/conditional.json').option]
}
function readSwitch (buffer, offset, { compareTo, fields, compareToValue, default: defVal }, rootNode) {
compareTo = compareToValue !== undefined ? compareToValue : getField(compareTo, rootNode)
if (typeof fields[compareTo] === 'undefined' && typeof defVal === 'undefined') { throw new Error(compareTo + ' has no associated fieldInfo in switch') }
for (const field in fields) {
if (field.startsWith('/')) {
fields[this.types[field.slice(1)]] = fields[field]
delete fields[field]
}
}
const caseDefault = typeof fields[compareTo] === 'undefined'
const resultingType = caseDefault ? defVal : fields[compareTo]
const fieldInfo = getFieldInfo(resultingType)
return tryDoc(() => this.read(buffer, offset, fieldInfo, rootNode), caseDefault ? 'default' : compareTo)
}
function writeSwitch (value, buffer, offset, { compareTo, fields, compareToValue, default: defVal }, rootNode) {
compareTo = compareToValue !== undefined ? compareToValue : getField(compareTo, rootNode)
if (typeof fields[compareTo] === 'undefined' && typeof defVal === 'undefined') { throw new Error(compareTo + ' has no associated fieldInfo in switch') }
for (const field in fields) {
if (field.startsWith('/')) {
fields[this.types[field.slice(1)]] = fields[field]
delete fields[field]
}
}
const caseDefault = typeof fields[compareTo] === 'undefined'
const fieldInfo = getFieldInfo(caseDefault ? defVal : fields[compareTo])
return tryDoc(() => this.write(value, buffer, offset, fieldInfo, rootNode), caseDefault ? 'default' : compareTo)
}
function sizeOfSwitch (value, { compareTo, fields, compareToValue, default: defVal }, rootNode) {
compareTo = compareToValue !== undefined ? compareToValue : getField(compareTo, rootNode)
if (typeof fields[compareTo] === 'undefined' && typeof defVal === 'undefined') { throw new Error(compareTo + ' has no associated fieldInfo in switch') }
for (const field in fields) {
if (field.startsWith('/')) {
fields[this.types[field.slice(1)]] = fields[field]
delete fields[field]
}
}
const caseDefault = typeof fields[compareTo] === 'undefined'
const fieldInfo = getFieldInfo(caseDefault ? defVal : fields[compareTo])
return tryDoc(() => this.sizeOf(value, fieldInfo, rootNode), caseDefault ? 'default' : compareTo)
}
function readOption (buffer, offset, typeArgs, context) {
if (buffer.length < offset + 1) { throw new PartialReadError() }
const val = buffer.readUInt8(offset++)
if (val !== 0) {
const retval = this.read(buffer, offset, typeArgs, context)
retval.size++
return retval
} else { return { size: 1 } }
}
function writeOption (value, buffer, offset, typeArgs, context) {
if (value != null) {
buffer.writeUInt8(1, offset++)
offset = this.write(value, buffer, offset, typeArgs, context)
} else { buffer.writeUInt8(0, offset++) }
return offset
}
function sizeOfOption (value, typeArgs, context) {
return value == null ? 1 : this.sizeOf(value, typeArgs, context) + 1
}