Skip to content

Commit

Permalink
Add bitflags
Browse files Browse the repository at this point in the history
  • Loading branch information
extremeheat committed Dec 5, 2024
1 parent 0686979 commit 4ffa831
Show file tree
Hide file tree
Showing 3 changed files with 133 additions and 7 deletions.
16 changes: 9 additions & 7 deletions example.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
const assert = require('assert')
const ProtoDef = require('protodef').ProtoDef
const Serializer = require('protodef').Serializer
const Parser = require('protodef').Parser
Expand All @@ -13,6 +14,7 @@ const exampleProtocol = {
byte: 'native',
bool: 'native',
switch: 'native',
bitflags: 'native',
entity_look: [
'container',
[
Expand All @@ -28,10 +30,7 @@ const exampleProtocol = {
name: 'pitch',
type: 'i8'
},
{
name: 'onGround',
type: 'bool'
},
{ name: 'flags', type: ['bitflags', { type: 'u8', flags: ['onGround'] }] },
{ name: 'longId', type: 'varint64' },
{ name: 'longerId', type: 'varint128' },
{ name: 'zigzagId', type: 'zigzag32' },
Expand Down Expand Up @@ -79,8 +78,10 @@ serializer.write({
params: {
entityId: 1,
yaw: 1,
pitch: 1,
onGround: true,
pitch: 6,
flags: {
onGround: true
},
longId: 13n,
longerId: 2n ** 68n, // 9 bytes integer, 10 over wire
zigzagId: -3,
Expand All @@ -90,5 +91,6 @@ serializer.write({
serializer.pipe(parser)

parser.on('data', function (chunk) {
console.log(JSON.stringify(chunk, null, 2))
console.log(chunk)
assert.deepEqual([...chunk.buffer], [22, 1, 1, 6, 1, 13, 128, 128, 128, 128, 128, 128, 128, 128, 128, 32, 5, 128, 128, 128, 128, 32])
})
61 changes: 61 additions & 0 deletions src/datatypes/compiler-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,27 @@ module.exports = {
code += 'return { value: { ' + names.join(', ') + ` }, size: ${totalBytes} }`
return compiler.wrapCode(code)
}],
bitflags: ['parametrizable', (compiler, { type, flags, shift, big }) => {
let fstr = JSON.stringify(flags)
if (Array.isArray(flags)) {
fstr = '{'
for (const [k, v] of Object.entries(flags)) fstr += `"${v}": ${big ? (1n << BigInt(k)) : (1 << k)}` + (big ? 'n,' : ',')
fstr += '}'
} else if (shift) {
fstr = '{'
for (const key in flags) fstr += `"${key}": ${1 << flags[key]},`
fstr += '}'
}
return compiler.wrapCode(`
const { value: _value, size } = ${compiler.callType(type, 'offset')}
const value = { _value }
const flags = ${fstr}
for (const key in flags) {
value[key] = (_value & flags[key]) == flags[key]
}
return { value, size }
`.trim())
}],
mapper: ['parametrizable', (compiler, mapper) => {
let code = 'const { value, size } = ' + compiler.callType(mapper.type) + '\n'
code += 'return { value: ' + JSON.stringify(sanitizeMappings(mapper.mappings)) + '[value] || value, size }'
Expand Down Expand Up @@ -116,6 +137,26 @@ module.exports = {
code += 'return offset'
return compiler.wrapCode(code)
}],
bitflags: ['parametrizable', (compiler, { type, flags, shift, big }) => {
let fstr = JSON.stringify(flags)
if (Array.isArray(flags)) {
fstr = '{'
for (const [k, v] of Object.entries(flags)) fstr += `"${v}": ${big ? (1n << BigInt(k)) : (1 << k)}` + (big ? 'n,' : ',')
fstr += '}'
} else if (shift) {
fstr = '{'
for (const key in flags) fstr += `"${key}": ${1 << flags[key]},`
fstr += '}'
}
return compiler.wrapCode(`
const flags = ${fstr}
let val = value._value ${big ? '|| 0n' : ''}
for (const key in flags) {
if (value[key]) val |= flags[key]
}
return (ctx.${type})(val, buffer, offset)
`.trim())
}],
mapper: ['parametrizable', (compiler, mapper) => {
const mappings = JSON.stringify(swapMappings(mapper.mappings))
const code = 'return ' + compiler.callType(`${mappings}[value] || value`, mapper.type)
Expand Down Expand Up @@ -148,6 +189,26 @@ module.exports = {
const totalBytes = Math.ceil(values.reduce((acc, { size }) => acc + size, 0) / 8)
return `${totalBytes}`
}],
bitflags: ['parametrizable', (compiler, { type, flags, shift, big }) => {
let fstr = JSON.stringify(flags)
if (Array.isArray(flags)) {
fstr = '{'
for (const [k, v] of Object.entries(flags)) fstr += `"${v}": ${big ? (1n << BigInt(k)) : (1 << k)}` + (big ? 'n,' : ',')
fstr += '}'
} else if (shift) {
fstr = '{'
for (const key in flags) fstr += `"${key}": ${1 << flags[key]},`
fstr += '}'
}
return compiler.wrapCode(`
const flags = ${fstr}
let val = value._value ${big ? '|| 0n' : ''}
for (const key in flags) {
if (value[key]) val |= flags[key]
}
return (ctx.${type})(val)
`.trim())
}],
mapper: ['parametrizable', (compiler, mapper) => {
const mappings = JSON.stringify(swapMappings(mapper.mappings))
const code = 'return ' + compiler.callType(`${mappings}[value] || value`, mapper.type)
Expand Down
63 changes: 63 additions & 0 deletions src/datatypes/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = {
buffer: [readBuffer, writeBuffer, sizeOfBuffer, require('../../ProtoDef/schemas/utils.json').buffer],
void: [readVoid, writeVoid, 0, require('../../ProtoDef/schemas/utils.json').void],
bitfield: [readBitField, writeBitField, sizeOfBitField, require('../../ProtoDef/schemas/utils.json').bitfield],
bitflags: [readBitflags, writeBitflags, sizeOfBitflags, require('../../ProtoDef/schemas/utils.json').bitflags],
cstring: [readCString, writeCString, sizeOfCString, require('../../ProtoDef/schemas/utils.json').cstring],
mapper: [readMapper, writeMapper, sizeOfMapper, require('../../ProtoDef/schemas/utils.json').mapper],
...require('./varint')
Expand Down Expand Up @@ -217,3 +218,65 @@ function sizeOfCString (value) {
const length = Buffer.byteLength(value, 'utf8')
return length + 1
}

function readBitflags (buffer, offset, { type, flags, shift, big }, rootNode) {
const { size, value } = this.read(buffer, offset, type, rootNode)
let f = {}
if (Array.isArray(flags)) {
for (const [k, v] of Object.entries(flags)) {
f[v] = big ? (1n << BigInt(k)) : (1 << k)
}
} else if (shift) {
for (const k in flags) {
f[k] = (big ? 1n : 1) << flags[k]
}
} else {
f = flags
}
const result = { _value: value }
for (const key in f) {
result[key] = (value & f[key]) === f[key]
}
return { value: result, size }
}

function writeBitflags (value, buffer, offset, { type, flags, shift, big }, rootNode) {
let f = {}
if (Array.isArray(flags)) {
for (const [k, v] of Object.entries(flags)) {
f[v] = big ? (1n << BigInt(k)) : (1 << k)
}
} else if (shift) {
for (const k in flags) {
f[k] = (big ? 1n : 1) << flags[k]
}
} else {
f = flags
}
let val = value._value || (big ? 0n : 0)
for (const key in f) {
if (value[key]) val |= f[key]
}
return this.write(val, buffer, offset, type, rootNode)
}

function sizeOfBitflags (value, { type, flags, shift, big }, rootNode) {
if (!value) throw new Error('Missing field')
let f = {}
if (Array.isArray(flags)) {
for (const [k, v] of Object.entries(flags)) {
f[v] = big ? (1n << BigInt(k)) : (1 << k)
}
} else if (shift) {
for (const k in flags) {
f[k] = (big ? 1n : 1) << flags[k]
}
} else {
f = flags
}
let mappedValue = value._value || (big ? 0n : 0)
for (const key in f) {
if (value[key]) mappedValue |= f[key]
}
return this.sizeOf(mappedValue, type, rootNode)
}

0 comments on commit 4ffa831

Please sign in to comment.