Skip to content

Commit

Permalink
feat: cli option to not encode/decode default values
Browse files Browse the repository at this point in the history
Resolves ipfs#43
  • Loading branch information
D4nte committed Jun 29, 2022
1 parent b634661 commit ae067a8
Show file tree
Hide file tree
Showing 27 changed files with 109 additions and 58 deletions.
6 changes: 4 additions & 2 deletions packages/protons-runtime/src/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,16 @@ export interface Codec<T> {
encode: EncodeFunction<T>
decode: DecodeFunction<T>
encodingLength: EncodingLengthFunction<T>
defaultValue: T
}

export function createCodec <T> (name: string, type: CODEC_TYPES, encode: EncodeFunction<T>, decode: DecodeFunction<T>, encodingLength: EncodingLengthFunction<T>): Codec<T> {
export function createCodec <T> (name: string, type: CODEC_TYPES, encode: EncodeFunction<T>, decode: DecodeFunction<T>, encodingLength: EncodingLengthFunction<T>, defaultValue: T): Codec<T> {
return {
name,
type,
encode,
decode,
encodingLength
encodingLength,
defaultValue
}
}
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/bool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,6 @@ const decode: DecodeFunction<boolean> = function boolDecode (buffer, offset) {
return buffer.get(offset) > 0
}

export const bool = createCodec('bool', CODEC_TYPES.VARINT, encode, decode, encodingLength)
const defaultValue: boolean = false

export const bool = createCodec('bool', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/bytes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ const decode: DecodeFunction<Uint8Array> = function bytesDecode (buf, offset) {
return buf.slice(offset, offset + byteLength)
}

export const bytes = createCodec('bytes', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength)
const defaultValue: Uint8Array = new Uint8Array()

export const bytes = createCodec('bytes', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength, defaultValue)
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/double.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ const decode: DecodeFunction<number> = function doubleDecode (buf, offset) {
return buf.getFloat64(offset, true)
}

export const double = createCodec('double', CODEC_TYPES.BIT64, encode, decode, encodingLength)
const defaultValue: number = 0

export const double = createCodec('double', CODEC_TYPES.BIT64, encode, decode, encodingLength, defaultValue)
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { unsigned } from '../utils/varint.js'
import { createCodec, CODEC_TYPES } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction, Codec } from '../codec.js'

const defaultValue: any = 0

export function enumeration <T> (v: any): Codec<T> {
function findValue (val: string | number): number {
if (v[val.toString()] == null) {
Expand Down Expand Up @@ -43,5 +45,5 @@ export function enumeration <T> (v: any): Codec<T> {
}

// @ts-expect-error yeah yeah
return createCodec('enum', CODEC_TYPES.VARINT, encode, decode, encodingLength)
return createCodec('enum', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
}
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/fixed32.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ const decode: DecodeFunction<number> = function fixed32Decode (buf, offset) {
return buf.getInt32(offset, true)
}

export const fixed32 = createCodec('fixed32', CODEC_TYPES.BIT32, encode, decode, encodingLength)
const defaultValue: number = 0

export const fixed32 = createCodec('fixed32', CODEC_TYPES.BIT32, encode, decode, encodingLength, defaultValue)
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/fixed64.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ const decode: DecodeFunction<bigint> = function int64Decode (buf, offset) {
return buf.getBigInt64(offset, true)
}

export const fixed64 = createCodec('fixed64', CODEC_TYPES.BIT64, encode, decode, encodingLength)
const defaultValue: bigint = 0n

export const fixed64 = createCodec('fixed64', CODEC_TYPES.BIT64, encode, decode, encodingLength, defaultValue)
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/float.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ const decode: DecodeFunction<number> = function floatDecode (buf, offset) {
return buf.getFloat32(offset, true)
}

export const float = createCodec('float', CODEC_TYPES.BIT32, encode, decode, encodingLength)
const defaultValue: number = 0

export const float = createCodec('float', CODEC_TYPES.BIT32, encode, decode, encodingLength, defaultValue)
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/int32.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ const decode: DecodeFunction<number> = function int32Decode (buf, offset) {
return signed.decode(buf, offset)
}

export const int32 = createCodec('int32', CODEC_TYPES.VARINT, encode, decode, encodingLength)
const defaultValue: number = 0

export const int32 = createCodec('int32', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/int64.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ const decode: DecodeFunction<bigint> = function int64Decode (buf, offset) {
return signed.decode(buf, offset) | 0n
}

export const int64 = createCodec('int64', CODEC_TYPES.VARINT, encode, decode, encodingLength)
const defaultValue: bigint = 0n

export const int64 = createCodec('int64', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
19 changes: 15 additions & 4 deletions packages/protons-runtime/src/codecs/message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,20 @@ import type { DecodeFunction, EncodeFunction, EncodingLengthFunction, Codec } fr
import { Uint8ArrayList } from 'uint8arraylist'
import type { FieldDefs, FieldDef } from '../index.js'

const defaultValue: any = {}

export interface Factory<A, T> {
new (obj: A): T
}

export function message <T> (fieldDefs: FieldDefs): Codec<T> {
export function message <T> (fieldDefs: FieldDefs, noDefaultOnWire: boolean): Codec<T> {
const encodingLength: EncodingLengthFunction<T> = function messageEncodingLength (val: Record<string, any>) {
let length = 0

for (const fieldDef of Object.values(fieldDefs)) {
length += fieldDef.codec.encodingLength(val[fieldDef.name])
if (!noDefaultOnWire || fieldDef.codec.defaultValue !== val[fieldDef.name]) {
length += fieldDef.codec.encodingLength(val[fieldDef.name])
}
}

return unsigned.encodingLength(length) + length
Expand All @@ -31,6 +35,10 @@ export function message <T> (fieldDefs: FieldDefs): Codec<T> {
throw new Error(`Non optional field "${fieldDef.name}" was ${value === null ? 'null' : 'undefined'}`)
}

if (noDefaultOnWire && value === fieldDef.codec.defaultValue) {
return
}

const key = (fieldNumber << 3) | fieldDef.codec.type
const prefix = new Uint8Array(unsigned.encodingLength(key))
unsigned.encode(key, prefix)
Expand Down Expand Up @@ -116,15 +124,18 @@ export function message <T> (fieldDefs: FieldDefs): Codec<T> {
offset += fieldLength
}

// make sure repeated fields have an array if not set
for (const fieldDef of Object.values(fieldDefs)) {
// make sure repeated fields have an array if not set
if (fieldDef.repeats === true && fields[fieldDef.name] == null) {
fields[fieldDef.name] = []
} else if (noDefaultOnWire && fields[fieldDef.name] == null) {
// apply default values if not set
fields[fieldDef.name] = fieldDef.codec.defaultValue
}
}

return fields
}

return createCodec('message', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength)
return createCodec('message', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength, defaultValue)
}
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/sfixed32.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ const decode: DecodeFunction<number> = function sfixed32Decode (buf, offset) {
return buf.getInt32(offset, true)
}

export const sfixed32 = createCodec('sfixed32', CODEC_TYPES.BIT32, encode, decode, encodingLength)
const defaultValue: number = 0

export const sfixed32 = createCodec('sfixed32', CODEC_TYPES.BIT32, encode, decode, encodingLength, defaultValue)
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/sfixed64.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ const decode: DecodeFunction<bigint> = function sfixed64Decode (buf, offset) {
return buf.getBigInt64(offset, true)
}

export const sfixed64 = createCodec('sfixed64', CODEC_TYPES.BIT64, encode, decode, encodingLength)
const defaultValue: bigint = 0n

export const sfixed64 = createCodec('sfixed64', CODEC_TYPES.BIT64, encode, decode, encodingLength, defaultValue)
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/sint32.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ const decode: DecodeFunction<number> = function svarintDecode (buf, offset) {
return zigzag.decode(buf, offset)
}

export const sint32 = createCodec('sint32', CODEC_TYPES.VARINT, encode, decode, encodingLength)
const defaultValue: number = 0

export const sint32 = createCodec('sint32', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/sint64.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ const decode: DecodeFunction<bigint> = function int64Decode (buf, offset) {
return zigzag.decode(buf, offset)
}

export const sint64 = createCodec('sint64', CODEC_TYPES.VARINT, encode, decode, encodingLength)
const defaultValue: bigint = 0n

export const sint64 = createCodec('sint64', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,6 @@ const decode: DecodeFunction<string> = function stringDecode (buf, offset) {
return uint8ArrayToString(buf.slice(offset, offset + strLen))
}

export const string = createCodec('string', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength)
const defaultValue: string = ''

export const string = createCodec('string', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength, defaultValue)
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/uint32.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ const decode: DecodeFunction<number> = function uint32Decode (buf, offset) {
// return value > 2147483647 ? value - 4294967296 : value
}

export const uint32 = createCodec('uint32', CODEC_TYPES.VARINT, encode, decode, encodingLength)
const defaultValue: number = 0

export const uint32 = createCodec('uint32', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
4 changes: 3 additions & 1 deletion packages/protons-runtime/src/codecs/uint64.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ const decode: DecodeFunction<bigint> = function uint64Decode (buf, offset) {
return unsigned.decode(buf, offset)
}

export const uint64 = createCodec('uint64', CODEC_TYPES.VARINT, encode, decode, encodingLength)
const defaultValue: bigint = 0n

export const uint64 = createCodec('uint64', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
5 changes: 5 additions & 0 deletions packages/protons/bin/protons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ async function main () {
Options
--output, -o Path to a directory to write transpiled typescript files into
--no-default-on-wire Do not encode default values over the wire, decode absent fields as default values
Examples
$ protons ./path/to/file.proto ./path/to/other/file.proto
Expand All @@ -19,6 +20,10 @@ async function main () {
output: {
type: 'string',
alias: 'o'
},
defaultOnWire: {
type: 'boolean',
default: true
}
}
})
Expand Down
13 changes: 7 additions & 6 deletions packages/protons/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ function defineFields (fields: Record<string, FieldDef>, messageDef: MessageDef,
})
}

function compileMessage (messageDef: MessageDef, moduleDef: ModuleDef): string {
function compileMessage (messageDef: MessageDef, moduleDef: ModuleDef, noDefaultOnWire: boolean): string {
if (isEnumDef(messageDef)) {
moduleDef.imports.add('enumeration')

Expand Down Expand Up @@ -158,7 +158,7 @@ export namespace ${messageDef.name} {
if (messageDef.nested != null) {
nested = '\n'
nested += Object.values(messageDef.nested)
.map(def => compileMessage(def, moduleDef).trim())
.map(def => compileMessage(def, moduleDef, noDefaultOnWire).trim())
.join('\n\n')
.split('\n')
.map(line => line.trim() === '' ? '' : ` ${line}`)
Expand Down Expand Up @@ -213,7 +213,7 @@ export interface ${messageDef.name} {
return `${fieldDef.id}: { name: '${name}', codec: ${codec}${fieldDef.options?.proto3_optional === true ? ', optional: true' : ''}${fieldDef.rule === 'repeated' ? ', repeats: true' : ''} }`
}).join(',\n ')}
})
}, ${noDefaultOnWire ? 'true' : 'false'})
}
export const encode = (obj: ${messageDef.name}): Uint8Array => {
Expand Down Expand Up @@ -242,7 +242,7 @@ interface ModuleDef {
globals: Record<string, ClassDef>
}

function defineModule (def: ClassDef): ModuleDef {
function defineModule (def: ClassDef, noDefaultOnWire: boolean): ModuleDef {
const moduleDef: ModuleDef = {
imports: new Set(),
importedTypes: new Set(),
Expand Down Expand Up @@ -280,14 +280,15 @@ function defineModule (def: ClassDef): ModuleDef {
for (const className of Object.keys(defs)) {
const classDef = defs[className]

moduleDef.compiled.push(compileMessage(classDef, moduleDef))
moduleDef.compiled.push(compileMessage(classDef, moduleDef, noDefaultOnWire))
}

return moduleDef
}

interface Flags {
output?: string
defaultOnWire: boolean
}

export async function generate (source: string, flags: Flags) {
Expand All @@ -299,7 +300,7 @@ export async function generate (source: string, flags: Flags) {
}

const def = JSON.parse(json)
const moduleDef = defineModule(def)
const moduleDef = defineModule(def, !flags.defaultOnWire)

let lines = [
'/* eslint-disable import/export */',
Expand Down
2 changes: 1 addition & 1 deletion packages/protons/test/fixtures/basic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export namespace Basic {
return message<Basic>({
1: { name: 'foo', codec: string },
2: { name: 'num', codec: int32 }
})
}, false)
}

export const encode = (obj: Basic): Uint8Array => {
Expand Down
4 changes: 2 additions & 2 deletions packages/protons/test/fixtures/circuit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export namespace CircuitRelay {
return message<Peer>({
1: { name: 'id', codec: bytes },
2: { name: 'addrs', codec: bytes, repeats: true }
})
}, false)
}

export const encode = (obj: Peer): Uint8Array => {
Expand All @@ -104,7 +104,7 @@ export namespace CircuitRelay {
2: { name: 'srcPeer', codec: CircuitRelay.Peer.codec(), optional: true },
3: { name: 'dstPeer', codec: CircuitRelay.Peer.codec(), optional: true },
4: { name: 'code', codec: CircuitRelay.Status.codec(), optional: true }
})
}, false)
}

export const encode = (obj: CircuitRelay): Uint8Array => {
Expand Down
Loading

0 comments on commit ae067a8

Please sign in to comment.