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 Jul 8, 2022
1 parent ae067a8 commit 37ddfa8
Show file tree
Hide file tree
Showing 22 changed files with 305 additions and 62 deletions.
16 changes: 13 additions & 3 deletions packages/protons-runtime/src/codec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,22 +22,32 @@ export interface EncodingLengthFunction<T> {
(value: T): number
}

export interface DefaultValueFunction<T> {
(): T
}

export interface IsDefaultValueFunction<T> {
(value: T): boolean
}

export interface Codec<T> {
name: string
type: CODEC_TYPES
encode: EncodeFunction<T>
decode: DecodeFunction<T>
encodingLength: EncodingLengthFunction<T>
defaultValue: T
defaultValue: DefaultValueFunction<T>
isDefaultValue: IsDefaultValueFunction<T>
}

export function createCodec <T> (name: string, type: CODEC_TYPES, encode: EncodeFunction<T>, decode: DecodeFunction<T>, encodingLength: EncodingLengthFunction<T>, defaultValue: T): Codec<T> {
export function createCodec<T> (name: string, type: CODEC_TYPES, encode: EncodeFunction<T>, decode: DecodeFunction<T>, encodingLength: EncodingLengthFunction<T>, defaultValue: DefaultValueFunction<T>, isDefaultValue: IsDefaultValueFunction<T>): Codec<T> {
return {
name,
type,
encode,
decode,
encodingLength,
defaultValue
defaultValue,
isDefaultValue
}
}
8 changes: 5 additions & 3 deletions packages/protons-runtime/src/codecs/bool.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'

const encodingLength: EncodingLengthFunction<boolean> = function boolEncodingLength () {
Expand All @@ -13,6 +13,8 @@ const decode: DecodeFunction<boolean> = function boolDecode (buffer, offset) {
return buffer.get(offset) > 0
}

const defaultValue: boolean = false
const defaultValue: DefaultValueFunction<boolean> = () => false

export const bool = createCodec('bool', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<boolean> = (value: boolean) => !value

export const bool = createCodec('bool', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue, isDefaultValue)
9 changes: 6 additions & 3 deletions packages/protons-runtime/src/codecs/bytes.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@

import { Uint8ArrayList } from 'uint8arraylist'
import { unsigned } from '../utils/varint.js'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'
import { equals } from 'uint8arrays/equals'

const encodingLength: EncodingLengthFunction<Uint8Array> = function bytesEncodingLength (val) {
const len = val.byteLength
Expand All @@ -24,6 +25,8 @@ const decode: DecodeFunction<Uint8Array> = function bytesDecode (buf, offset) {
return buf.slice(offset, offset + byteLength)
}

const defaultValue: Uint8Array = new Uint8Array()
const defaultValue: DefaultValueFunction<Uint8Array> = () => new Uint8Array()

export const bytes = createCodec('bytes', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<Uint8Array> = (value: Uint8Array) => equals(value, defaultValue())

export const bytes = createCodec('bytes', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength, defaultValue, isDefaultValue)
8 changes: 5 additions & 3 deletions packages/protons-runtime/src/codecs/double.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Uint8ArrayList } from 'uint8arraylist'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'

const encodingLength: EncodingLengthFunction<number> = function doubleEncodingLength () {
Expand All @@ -17,6 +17,8 @@ const decode: DecodeFunction<number> = function doubleDecode (buf, offset) {
return buf.getFloat64(offset, true)
}

const defaultValue: number = 0
const defaultValue: DefaultValueFunction<number> = () => 0

export const double = createCodec('double', CODEC_TYPES.BIT64, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<number> = (value) => value === defaultValue()

export const double = createCodec('double', CODEC_TYPES.BIT64, encode, decode, encodingLength, defaultValue, isDefaultValue)
14 changes: 10 additions & 4 deletions packages/protons-runtime/src/codecs/enum.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@

import { unsigned } from '../utils/varint.js'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } 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 @@ -44,6 +42,14 @@ export function enumeration <T> (v: any): Codec<T> {
return v[strValue]
}

const defaultValue: DefaultValueFunction<number | string> = function defaultValue () {
return Object.values(v)[0] as (string | number)
}

const isDefaultValue: IsDefaultValueFunction<number| string> = function isDefaultValue (val) {
return val === defaultValue()
}

// @ts-expect-error yeah yeah
return createCodec('enum', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
return createCodec('enum', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue, isDefaultValue)
}
8 changes: 5 additions & 3 deletions packages/protons-runtime/src/codecs/fixed32.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Uint8ArrayList } from 'uint8arraylist'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'

const encodingLength: EncodingLengthFunction<number> = function fixed32EncodingLength () {
Expand All @@ -17,6 +17,8 @@ const decode: DecodeFunction<number> = function fixed32Decode (buf, offset) {
return buf.getInt32(offset, true)
}

const defaultValue: number = 0
const defaultValue: DefaultValueFunction<number> = () => 0

export const fixed32 = createCodec('fixed32', CODEC_TYPES.BIT32, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<number> = (val) => val === defaultValue()

export const fixed32 = createCodec('fixed32', CODEC_TYPES.BIT32, encode, decode, encodingLength, defaultValue, isDefaultValue)
8 changes: 5 additions & 3 deletions packages/protons-runtime/src/codecs/fixed64.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Uint8ArrayList } from 'uint8arraylist'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'

const encodingLength: EncodingLengthFunction<bigint> = function int64EncodingLength (val) {
Expand All @@ -17,6 +17,8 @@ const decode: DecodeFunction<bigint> = function int64Decode (buf, offset) {
return buf.getBigInt64(offset, true)
}

const defaultValue: bigint = 0n
const defaultValue: DefaultValueFunction<bigint> = () => 0n

export const fixed64 = createCodec('fixed64', CODEC_TYPES.BIT64, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<bigint> = (val) => val === defaultValue()

export const fixed64 = createCodec('fixed64', CODEC_TYPES.BIT64, encode, decode, encodingLength, defaultValue, isDefaultValue)
8 changes: 5 additions & 3 deletions packages/protons-runtime/src/codecs/float.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Uint8ArrayList } from 'uint8arraylist'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'

const encodingLength: EncodingLengthFunction<number> = function floatEncodingLength () {
Expand All @@ -17,6 +17,8 @@ const decode: DecodeFunction<number> = function floatDecode (buf, offset) {
return buf.getFloat32(offset, true)
}

const defaultValue: number = 0
const defaultValue: DefaultValueFunction<number> = () => 0

export const float = createCodec('float', CODEC_TYPES.BIT32, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<number> = (val) => val === defaultValue()

export const float = createCodec('float', CODEC_TYPES.BIT32, encode, decode, encodingLength, defaultValue, isDefaultValue)
8 changes: 5 additions & 3 deletions packages/protons-runtime/src/codecs/int32.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { signed } from '../utils/varint.js'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'

const encodingLength: EncodingLengthFunction<number> = function int32EncodingLength (val) {
Expand All @@ -17,6 +17,8 @@ const decode: DecodeFunction<number> = function int32Decode (buf, offset) {
return signed.decode(buf, offset)
}

const defaultValue: number = 0
const defaultValue: DefaultValueFunction<number> = () => 0

export const int32 = createCodec('int32', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<number> = (val) => val === defaultValue()

export const int32 = createCodec('int32', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue, isDefaultValue)
8 changes: 5 additions & 3 deletions packages/protons-runtime/src/codecs/int64.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { signed } from '../utils/big-varint.js'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'

const encodingLength: EncodingLengthFunction<bigint> = function int64EncodingLength (val) {
Expand All @@ -17,6 +17,8 @@ const decode: DecodeFunction<bigint> = function int64Decode (buf, offset) {
return signed.decode(buf, offset) | 0n
}

const defaultValue: bigint = 0n
const defaultValue: DefaultValueFunction<bigint> = () => 0n

export const int64 = createCodec('int64', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<bigint> = (val) => val === defaultValue()

export const int64 = createCodec('int64', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue, isDefaultValue)
48 changes: 39 additions & 9 deletions packages/protons-runtime/src/codecs/message.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { unsigned } from '../utils/varint.js'
import { createCodec, CODEC_TYPES } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction, Codec } from '../codec.js'
import type {
Codec,
DecodeFunction,
DefaultValueFunction,
EncodeFunction,
EncodingLengthFunction,
IsDefaultValueFunction
} from '../codec.js'
import { CODEC_TYPES, createCodec } from '../codec.js'
import { Uint8ArrayList } from 'uint8arraylist'
import type { FieldDefs, FieldDef } from '../index.js'

const defaultValue: any = {}
import type { FieldDef, FieldDefs } from '../index.js'

export interface Factory<A, T> {
new (obj: A): T
Expand All @@ -15,7 +20,7 @@ export function message <T> (fieldDefs: FieldDefs, noDefaultOnWire: boolean): Co
let length = 0

for (const fieldDef of Object.values(fieldDefs)) {
if (!noDefaultOnWire || fieldDef.codec.defaultValue !== val[fieldDef.name]) {
if (!noDefaultOnWire || !fieldDef.codec.isDefaultValue(val[fieldDef.name])) {
length += fieldDef.codec.encodingLength(val[fieldDef.name])
}
}
Expand All @@ -35,7 +40,7 @@ export function message <T> (fieldDefs: FieldDefs, noDefaultOnWire: boolean): Co
throw new Error(`Non optional field "${fieldDef.name}" was ${value === null ? 'null' : 'undefined'}`)
}

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

Expand Down Expand Up @@ -130,12 +135,37 @@ export function message <T> (fieldDefs: FieldDefs, noDefaultOnWire: boolean): Co
fields[fieldDef.name] = []
} else if (noDefaultOnWire && fields[fieldDef.name] == null) {
// apply default values if not set
fields[fieldDef.name] = fieldDef.codec.defaultValue
fields[fieldDef.name] = fieldDef.codec.defaultValue()
}
}

return fields
}

return createCodec('message', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength, defaultValue)
// Need to initialized sub messages as default value.
const defaultValue: DefaultValueFunction<T> = function defaultValue () {
const defaultValue: any = {}

for (const fieldDef of Object.values(fieldDefs)) {
if (fieldDef.codec.type === CODEC_TYPES.LENGTH_DELIMITED) {
defaultValue[fieldDef.name] = fieldDef.codec.defaultValue()
}
}

return defaultValue
}

const isDefaultValue: IsDefaultValueFunction<T> = function isDefaultValue (val) {
for (const fieldDef of Object.values(fieldDefs)) {
// @ts-expect-error
const fieldValue = val[fieldDef.name]

if (!fieldDef.codec.isDefaultValue(fieldValue)) {
return false
}
}
return true
}

return createCodec('message', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength, defaultValue, isDefaultValue)
}
8 changes: 5 additions & 3 deletions packages/protons-runtime/src/codecs/sfixed32.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Uint8ArrayList } from 'uint8arraylist'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'

const encodingLength: EncodingLengthFunction<number> = function sfixed32EncodingLength () {
Expand All @@ -17,6 +17,8 @@ const decode: DecodeFunction<number> = function sfixed32Decode (buf, offset) {
return buf.getInt32(offset, true)
}

const defaultValue: number = 0
const defaultValue: DefaultValueFunction<number> = () => 0

export const sfixed32 = createCodec('sfixed32', CODEC_TYPES.BIT32, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<number> = (val) => val === defaultValue()

export const sfixed32 = createCodec('sfixed32', CODEC_TYPES.BIT32, encode, decode, encodingLength, defaultValue, isDefaultValue)
8 changes: 5 additions & 3 deletions packages/protons-runtime/src/codecs/sfixed64.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Uint8ArrayList } from 'uint8arraylist'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'

const encodingLength: EncodingLengthFunction<bigint> = function sfixed64EncodingLength () {
Expand All @@ -17,6 +17,8 @@ const decode: DecodeFunction<bigint> = function sfixed64Decode (buf, offset) {
return buf.getBigInt64(offset, true)
}

const defaultValue: bigint = 0n
const defaultValue: DefaultValueFunction<bigint> = () => 0n

export const sfixed64 = createCodec('sfixed64', CODEC_TYPES.BIT64, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<bigint> = (val) => val === defaultValue()

export const sfixed64 = createCodec('sfixed64', CODEC_TYPES.BIT64, encode, decode, encodingLength, defaultValue, isDefaultValue)
8 changes: 5 additions & 3 deletions packages/protons-runtime/src/codecs/sint32.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { zigzag } from '../utils/varint.js'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'

const encodingLength: EncodingLengthFunction<number> = function sint32EncodingLength (val) {
Expand All @@ -18,6 +18,8 @@ const decode: DecodeFunction<number> = function svarintDecode (buf, offset) {
return zigzag.decode(buf, offset)
}

const defaultValue: number = 0
const defaultValue: DefaultValueFunction<number> = () => 0

export const sint32 = createCodec('sint32', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<number> = (val) => val === defaultValue()

export const sint32 = createCodec('sint32', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue, isDefaultValue)
8 changes: 5 additions & 3 deletions packages/protons-runtime/src/codecs/sint64.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { zigzag } from '../utils/big-varint.js'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'

const encodingLength: EncodingLengthFunction<bigint> = function int64EncodingLength (val) {
Expand All @@ -17,6 +17,8 @@ const decode: DecodeFunction<bigint> = function int64Decode (buf, offset) {
return zigzag.decode(buf, offset)
}

const defaultValue: bigint = 0n
const defaultValue: DefaultValueFunction<bigint> = () => 0n

export const sint64 = createCodec('sint64', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<bigint> = (val) => val === defaultValue()

export const sint64 = createCodec('sint64', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue, isDefaultValue)
8 changes: 5 additions & 3 deletions packages/protons-runtime/src/codecs/string.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { unsigned } from '../utils/varint.js'
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'
import { Uint8ArrayList } from 'uint8arraylist'

Expand All @@ -26,6 +26,8 @@ const decode: DecodeFunction<string> = function stringDecode (buf, offset) {
return uint8ArrayToString(buf.slice(offset, offset + strLen))
}

const defaultValue: string = ''
const defaultValue: DefaultValueFunction<string> = () => ''

export const string = createCodec('string', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<string> = (val) => val === defaultValue()

export const string = createCodec('string', CODEC_TYPES.LENGTH_DELIMITED, encode, decode, encodingLength, defaultValue, isDefaultValue)
8 changes: 5 additions & 3 deletions packages/protons-runtime/src/codecs/uint32.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { unsigned } from '../utils/varint.js'
import { createCodec, CODEC_TYPES } from '../codec.js'
import { createCodec, CODEC_TYPES, DefaultValueFunction, IsDefaultValueFunction } from '../codec.js'
import type { DecodeFunction, EncodeFunction, EncodingLengthFunction } from '../codec.js'

const encodingLength: EncodingLengthFunction<number> = function uint32EncodingLength (val) {
Expand All @@ -22,6 +22,8 @@ const decode: DecodeFunction<number> = function uint32Decode (buf, offset) {
// return value > 2147483647 ? value - 4294967296 : value
}

const defaultValue: number = 0
const defaultValue: DefaultValueFunction<number> = () => 0

export const uint32 = createCodec('uint32', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue)
const isDefaultValue: IsDefaultValueFunction<number> = (val) => val === defaultValue()

export const uint32 = createCodec('uint32', CODEC_TYPES.VARINT, encode, decode, encodingLength, defaultValue, isDefaultValue)
Loading

0 comments on commit 37ddfa8

Please sign in to comment.