- Are you stuck with integrating with a system that only speaks binary?
- Are you sick of manually decoding and encoding from json to binary?
- Do you want an easy way to define your types in javascript?
If you answered yes to any of the above questions, then bison-types
is for you
bison-types
allows you to define custom types.
With these custom types you can build up a message definition
Pass these types and the buffer to bison-types and it will do the rest.
For example:
bison = require 'bison-types'
types = bison.preCompile
# top-level type
'timeline': [
{count: 'uint16'}
{messages: 'message[count]'}
]
# sub type
'message': [
{id: 'uint8'}
{timestamp: 'uint16'}
{length: 'uint16'}
{text: 'utf-8(length)'}
]
# time to read!
buf = new Buffer [0x04, 0x92, 0x04, 0x3b, 0xf4, 0x2c, ...]
reader = new bison.Reader buf, types, {bigEndian: false}
json = reader.read 'timeline'
# or write !
buf = new Buffer(1024)
writer = new bison.Writer buf, types, {bigEndian: false}
writer.write 'timeline', {
count: 1
messages: [
{
id: 3
date: new Date().getTime()
length: 11
text: 'hello world'
}
]
}
Note: bison-types uses clever-buffer under the hood for all buffer manipulation.
The following types can be declared as a string, for example: {timestamp: 'uint16'}
.
uint8
- unsigned 8 bit integeruint16
- unsigned 16 bit integeruint32
- unsigned 32 bit integeruint64
- unsigned 64 bit integerint8
- signed 8 bit integerint16
- signed 16 bit integerint32
- signed 32 bit integerint64
- signed 64 bit integerutf-8
- utf-8 encoded stringbool
- boolean (stored as 8 bit integer)skip
- will skip specified bytes
There is also an enumeration
type, which can be used to represent enums from arrays of objects:
# will store the index in the array
levelIndex = bison.enumeration 'uint8', ['admin', 'reader', 'writer']
# will store the value in the object
levelCode = bison.enumeration 'uint16',
'admin': 0xb8a3
'reader': 0xb90a
'writer': 0xf23c
bison.preCompile
'levelIndex': levelIndex
'levelCode': levelCode
'user': [
{id: 'uint8'}
{levelX: levelIndex}
{levelY: levelCode}
]
There are 2 different ways that you can define a custom type
types = bison.preCompile
my-other-type: [
{a: 'uint8'}
{b: 'uint16'}
]
my-type: [
{c: 'my-other-type'}
{d: 'uint8'}
]
would create an object like
myType = {c: {a: 12, b: 123}, d: 1234}
We expose the underlying clever-buffer as @buffer.
You can call any of its methods
types = bison.preCompile
multiply:
_read: (multiplier) ->
@buffer.getUint8() * multiplier
_write: (val, multiplier) ->
@buffer.writeUInt8(val * multiplier)
would multiply the value read from the buffer before returning it when reading and multiply the value to be written when writing
You need to pass in a buffer to read from, and any custom types that you may have.
You can also pass in options, look at clever-buffer for a full list of options
bison = require 'bison-types'
buf = new Buffer [ 0x01, 0x02, 0x03, 0x04 ]
types = bison.preCompile
my-type: [
{a: 'uint8'}
{b: 'uint8'}
{c: 'uint8'}
{d: 'uint8'}
]
options = {bigEndian: false}
reader = new bison.Reader buf, types, options
myType = reader.read('my-type') # myType = { a: 1, b: 2, c: 3, d: 4 }
bison = require 'bison-types'
buf = new Buffer [0x48, 0x45, 0x4C, 0x4C, 0x4F]
types = bison.preCompile
my-type: [
a: 'utf-8(5)'
]
options = {bigEndian: false}
reader = new bison.Reader buf, types, options
myType = reader.read('my-type') # myType = { a: 'HELLO' }
The power of bison-types is evident as you define more complex types
bison = require 'bison-types'
buf = new Buffer [ 0x01, 0x03, 0x04 ]
types = bison.preCompile
my-type: [
{a: 'uint8'}
{b: 'my-other-type'}
]
my-other-type: [
{c: 'uint8'}
{d: 'uint8'}
]
options = {bigEndian: false}
reader = new bison.Reader buf, types, options
myType = reader.read('my-type') # myType = { a: 1, b: { c: 3, d: 4 }}
You can use previously resolved values as parameters to types The power of bison-types is evident as you define more complex types
bison = require 'bison-types'
buf = new Buffer [ 0x04, 0x02 ]
types = bison.preCompile
mult:
_read: (val) -> @buffer.getUInt8() * val
my-type: [
{a: 'uint8'}
{b: 'mult(a)'}
]
options = {bigEndian: false}
reader = new bison.Reader buf, types, options
myType = reader.read('my-type') # myType = { a: 4, b: 8}
You can specify arrays in a similar matter
bison = require 'bison-types'
buf = new Buffer [ 0x03, 0x01, 0x02, 0x03 ]
types = bison.preCompile
object: [
c: 'uint8'
]
my-type: [
{a: 'uint8'}
{b: 'object[a]'}
]
options = {bigEndian: false}
reader = new bison.Reader buf, types, options
myType = reader.read('my-type')
# myType = { a: 3, b:[{c:1},{c:2},{c:3}] }
You need to pass in a buffer to write to, and any custom types that you may have.
You can also pass in options, look at clever-buffer for a full list of options
bison = require 'bison-types'
buf = new Buffer 4
types = bison.preCompile
my-type: [
{a: 'uint8'}
{b: 'uint8'}
{c: 'uint8'}
{d: 'uint8'}
]
options = {bigEndian: false}
writer = new bison.Writer buf, types, options
writer.write 'my-type', { a: 1, b: 2, c: 3, d: 4 }
# buf will equal [ 0x01, 0x02, 0x03, 0x04 ]
bison = require 'bison-types'
buf = new Buffer 5
types = bison.preCompile
my-type: [
a: 'utf-8'
]
options = {bigEndian: false}
writer = new bison.Writer buf, types, options
writer.write 'my-type', { a: 'HELLO' }
# buf will equal [0x48, 0x45, 0x4C, 0x4C, 0x4F]
bison = require 'bison-types'
buf = new Buffer 10
types = bison.preCompile
my-type: [
a: 'utf-8(5)'
]
options = {bigEndian: false}
writer = new bison.Writer buf, types, options
writer.write 'my-type', { a: 'HELLOWORLD' }
# buf will equal [0x48, 0x45, 0x4C, 0x4C, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00]
The power of bison-types is evident as you define more complex types
bison = require 'bison-types'
buf = new Buffer 4
types = bison.preCompile
my-type: [
{a: 'uint8'}
{b: 'my-other-type'}
]
my-other-type: [
{c: 'uint8'}
{d: 'uint8'}
]
options = {bigEndian: false}
writer = new bison.Writer buf, types, options
writer.write 'my-type', { a: 1, b: { c: 3, d: 4 }}
# buf will equal [ 0x01, 0x03, 0x04 ]
You can use other values as parameters to types The power of bison-types is evident as you define more complex types
bison = require 'bison-types'
buf = new Buffer 2
types = bison.preCompile
div:
_write: (val, divider) -> @buffer.writeUInt8(val/divider)
my-type: [
{a: 'uint8'}
{b: 'div(a)'}
]
options = {bigEndian: false}
writer = new bison.Writer buf, types, options
writer.write 'my-type', { a: 4, b: 8}
# buf will equal [ 0x04, 0x02 ]
You can specify a specific value using the following syntax
bison = require 'bison-types'
buf = new Buffer 2
types = bison.preCompile
my-type: [
{a: 'uint8=1'}
{b: 'uint8=2'}
]
options = {bigEndian: false}
writer = new bison.Writer buf, types, options
writer.write 'my-type', {}
# buf will equal [ 0x01, 0x02 ]
You can specify arrays in a similar matter
bison = require 'bison-types'
buf = new Buffer 4
types = bison.preCompile
object: [
c: 'uint8'
]
my-type: [
{a: 'uint8'}
{b: 'object[a]'}
]
options = {bigEndian: false}
writer = new bison.Writer buf, types, options
writer.write 'my-type', { a: 3, b:[{c:1},{c:2},{c:3}] }
# buf will equal [ 0x03, 0x01, 0x02, 0x03 ]
This is a shorthand of the above example
bison = require 'bison-types'
buf = new Buffer 4
types = bison.preCompile
object: [
c: 'uint8'
]
my-type: [
{a: 'uint8=b.length'}
{b: 'object[b.length]'}
]
options = {bigEndian: false}
writer = new bison.Writer buf, types, options
writer.write 'my-type', { b:[{c:1},{c:2},{c:3}] }
# buf will equal [ 0x03, 0x01, 0x02, 0x03 ]
npm test