ubjson

package module
v1.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 18, 2021 License: MIT Imports: 11 Imported by: 2

README

UBJSON GoDoc Build Status Go Report Card

A Go package implementing encoding and decoding of Universal Binary JSON (spec 12).

Features

  • Type specific methods for built-in types.

  • Automatic encoding via reflection for most types.

  • Custom encoding via Value interface.

  • Streaming support via Encoder/Decoder.

  • Support for optimized format.

  • Block format.

Usage

b, _ := ubjson.MarshalBlock(8)
// [U][8]

b, _ = ubjson.MarshalBlock("hello")
// [S][U][5][hello]

var v interface{}
...
b, _ = ubjson.Marshal(v)
// ...

See the GoDoc for more information and examples.

Documentation

Overview

Package ubjson implements encoding and decoding of UBJSON (spec 12). http://ubjson.org/

Most types can be automatically encoded through reflection with the Marshal and Unmarshal functions. Encoders and Decoders additionally provide type specific methods. Custom encodings can be defined by implementing the Value interface. 'ubjson' struct tags can be used to override field names.

b, _ := ubjson.MarshalBlock(8)
// [U][8]
b, _ = ubjson.MarshalBlock("hello")
// [S][U][5][hello]
var v interface{}
...
b, _ = ubjson.Marshal(v)
// ...
Example (CustomValue)
package main

import (
	"fmt"

	"github.com/jmank88/ubjson"
)

// A CustomValue encodes itself as a fixed length object container.
type CustomValue struct {
	Field1 string
	FieldA int
}

func (c *CustomValue) UBJSONType() ubjson.Marker {
	return ubjson.ObjectStartMarker
}

func (c *CustomValue) MarshalUBJSON(e *ubjson.Encoder) error {
	o, err := e.ObjectLen(2)
	if err != nil {
		return err
	}
	if err := o.EncodeKey("Field1"); err != nil {
		return err
	}
	if err := o.EncodeString(c.Field1); err != nil {
		return err
	}
	if err := o.EncodeKey("FieldA"); err != nil {
		return err
	}
	if err := o.EncodeInt(c.FieldA); err != nil {
		return err
	}
	return o.End()
}

func (c *CustomValue) UnmarshalUBJSON(d *ubjson.Decoder) error {
	o, err := d.Object()
	if err != nil {
		return err
	}
	for o.NextEntry() {
		k, err := o.DecodeKey()
		if err != nil {
			return err
		}
		switch k {
		case "Field1":
			s, err := o.DecodeString()
			if err != nil {
				return err
			}
			c.Field1 = s
		case "FieldA":
			i, err := o.DecodeInt()
			if err != nil {
				return err
			}
			c.FieldA = i
		}
	}
	return o.End()
}

func main() {
	v := &CustomValue{Field1: "test", FieldA: 42}
	if b, err := ubjson.MarshalBlock(v); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}

}
Output:

[{][#][U][2]
	[U][6][Field1][S][U][4][test]
	[U][6][FieldA][U][42]
Example (Pair)
package main

import (
	"fmt"

	"github.com/jmank88/ubjson"
)

// A Int8Vec3 encodes itself as a fixed length, strongly-typed array container.
type Int8Vec3 struct {
	a, b, c int8
}

func (iv *Int8Vec3) UBJSONType() ubjson.Marker {
	return ubjson.ArrayStartMarker
}

func (iv *Int8Vec3) MarshalUBJSON(e *ubjson.Encoder) error {
	a, err := e.ArrayType(ubjson.Int8Marker, 3)
	if err != nil {
		return err
	}
	if err := a.EncodeInt8(iv.a); err != nil {
		return err
	}
	if err := a.EncodeInt8(iv.b); err != nil {
		return err
	}
	if err := a.EncodeInt8(iv.c); err != nil {
		return err
	}
	return a.End()
}

func (iv *Int8Vec3) UnmarshalUBJSON(d *ubjson.Decoder) error {
	a, err := d.Array()
	if err != nil {
		return err
	}
	if i, err := a.DecodeInt8(); err != nil {
		return err
	} else {
		iv.a = i
	}
	if i, err := a.DecodeInt8(); err != nil {
		return err
	} else {
		iv.b = i
	}
	if i, err := a.DecodeInt8(); err != nil {
		return err
	} else {
		iv.c = i
	}
	return a.End()
}

func main() {
	iv := &Int8Vec3{a: 100, b: 42, c: -55}
	if b, err := ubjson.MarshalBlock(iv); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}

}
Output:

[[][$][i][#][U][3]
	[100]
	[42]
	[-55]
Example (StructAsArray)
package main

import (
	"fmt"

	"github.com/jmank88/ubjson"
)

// A Nameless struct encodes itself as a fixed length, ordered Array container,
// omitting the string names to save space.
type Nameless struct {
	Field1 string
	FieldA int8
}

func (n *Nameless) UBJSONType() ubjson.Marker {
	return ubjson.ArrayStartMarker
}

func (n *Nameless) MarshalUBJSON(e *ubjson.Encoder) error {
	a, err := e.ArrayLen(2)
	if err != nil {
		return err
	}
	if err := a.EncodeString(n.Field1); err != nil {
		return err
	}
	if err := a.EncodeInt8(n.FieldA); err != nil {
		return err
	}
	return a.End()
}

func (n *Nameless) UnmarshalUBJSON(d *ubjson.Decoder) error {
	a, err := d.Array()
	if err != nil {
		return err
	}
	n.Field1, err = d.DecodeString()
	if err != nil {
		return err
	}
	n.FieldA, err = d.DecodeInt8()
	if err != nil {
		return err
	}
	return a.End()
}

func main() {
	if b, err := ubjson.MarshalBlock(&Nameless{Field1: "test", FieldA: 42}); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}
}
Output:

[[][#][U][2]
	[S][U][4][test]
	[i][42]
Example (TaggedStruct)
package main

import (
	"fmt"

	"github.com/jmank88/ubjson"
)

// A TaggedStruct has fields with 'ubjson' tags.
type TaggedStruct struct {
	Field1 string `ubjson:"field1"`
	FieldA int    `json:"ignored" ubjson:"fieldA"`
}

func main() {
	v := &TaggedStruct{Field1: "test", FieldA: 42}
	if b, err := ubjson.MarshalBlock(v); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}

}
Output:

[{]
	[U][6][field1][S][U][4][test]
	[U][6][fieldA][U][42]
[}]

Index

Examples

Constants

View Source
const MaxCollectionAlloc = 1 << 24

MaxCollectionAlloc is the default maximum collection capacity allocation. Can be overridden via Decoder.MaxCollectionAlloc.

Variables

This section is empty.

Functions

func Marshal

func Marshal(v interface{}) ([]byte, error)

Marshal encodes a value into UBJSON. Types implementing Value will be encoded with their UBJSONType and MarshalUBJSON methods.

func MarshalBlock

func MarshalBlock(v interface{}) ([]byte, error)

MarshalBlock encodes a value into UBJSON block-notation. Types implementing Value will be encoded with their UBJSONType and MarshalUBJSON methods.

Example
package main

import (
	"fmt"

	"github.com/jmank88/ubjson"
)

func main() {
	if b, err := ubjson.MarshalBlock(8); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}

}
Output:

[U][8]
Example (Array)
package main

import (
	"fmt"

	"github.com/jmank88/ubjson"
)

func main() {
	if b, err := ubjson.MarshalBlock([]byte("testbytes")); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}

}
Output:

[[][$][U][#][U][9]
	[116]
	[101]
	[115]
	[116]
	[98]
	[121]
	[116]
	[101]
	[115]
Example (Ints)
package main

import (
	"fmt"

	"github.com/jmank88/ubjson"
)

func main() {
	if b, err := ubjson.MarshalBlock(8); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}
	if b, err := ubjson.MarshalBlock(-42); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}
	if b, err := ubjson.MarshalBlock(256); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}

}
Output:

[U][8]
[i][-42]
[I][256]
Example (Object)
package main

import (
	"fmt"

	"github.com/jmank88/ubjson"
)

func main() {
	type object struct {
		Str   string
		Int   int64
		Bytes []byte
	}
	o := &object{Str: "str", Int: 45678, Bytes: []byte("test")}
	if b, err := ubjson.MarshalBlock(o); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}

}
Output:

[{]
	[U][3][Str][S][U][3][str]
	[U][3][Int][L][45678]
	[U][5][Bytes][[][$][U][#][U][4]
		[116]
		[101]
		[115]
		[116]
[}]

func Unmarshal

func Unmarshal(binary []byte, v interface{}) error

Unmarshal decodes a value from UBJSON. Types implementing Value will be decoded via their UBJSONType and UnmarshalUBJSON methods.

func UnmarshalBlock

func UnmarshalBlock(block []byte, v interface{}) error

UnmarshalBlock decodes a value from UBJSON block-notation. Types implementing Value will be encoded with their UBJSONType and MarshalUBJSON methods.

Types

type ArrayDecoder

type ArrayDecoder struct {
	Decoder
	// Element type, or 0 if not present.
	ElemType Marker
	// Number of elements, or -1 if not present.
	Len int
	// contains filtered or unexported fields
}

An ArrayDecoder is a Decoder for array container elements.

func (*ArrayDecoder) End

func (a *ArrayDecoder) End() error

End completes array decoding and must be called. It may return errors (1) deferred from element decoding, (2) from a missing array end marker, or (3) from a length vs. count mismatch.

func (*ArrayDecoder) NextElem

func (a *ArrayDecoder) NextElem() bool

NextElem returns true when there is another element to decode, or false if the end of the array has been reached or an error is encountered, in which case it will be returned by the End method.

type ArrayEncoder

type ArrayEncoder struct {
	Encoder
	// contains filtered or unexported fields
}

An ArrayEncoder supplements an Encoder with an End() method, and performs validation and optimization of array elements. Callers must finish with a call to End().

func (*ArrayEncoder) End

func (a *ArrayEncoder) End() error

End completes array encoding.

type Char

type Char byte

A Char is a byte which is encoded as 'C' instead of 'U'. Must be <=127.

Example
package main

import (
	"fmt"

	"github.com/jmank88/ubjson"
)

func main() {
	// Single `byte`s (and `uint8`s) normally use the UInt8 marker.
	if b, err := ubjson.MarshalBlock(byte('a')); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}
	// The `Char` type uses the Char marker instead.
	if b, err := ubjson.MarshalBlock(ubjson.Char('a')); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}

}
Output:

[U][97]
[C][a]

type Decoder

type Decoder struct {

	// Limits the capacity of allocated collections and returns errors rather
	// than risking waste or panicking on unreasonable/malicious input.
	// Example: "[[][$][T][#][l][999999999999999999]".
	// New Decoders default to package const MaxCollectionAlloc.
	MaxCollectionAlloc int
	// contains filtered or unexported fields
}

Decoder provides methods for decoding UBJSON data types.

func NewBlockDecoder

func NewBlockDecoder(r io.Reader) *Decoder

NewBlockDecoder returns a new block-notation Decoder.

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder returns a new Decoder.

func (*Decoder) Array

func (d *Decoder) Array() (*ArrayDecoder, error)

Array begins decoding an array, and returns a specialized decoder for array elements.

func (*Decoder) Decode

func (d *Decoder) Decode(v interface{}) error

Decode decodes a value into v by delegating to the appropriate type-specific method. Recognizes the special types Char and HighPrecNumber to distinguish from backing types.

func (*Decoder) DecodeArray

func (d *Decoder) DecodeArray(decodeData func(*ArrayDecoder) error) error

DecodeArray decodes an array container.

func (*Decoder) DecodeBool

func (d *Decoder) DecodeBool() (bool, error)

DecodeBool decodes a 'T' or 'F' marker.

func (*Decoder) DecodeChar

func (d *Decoder) DecodeChar() (byte, error)

DecodeChar decodes a 'C' value into a byte.

func (*Decoder) DecodeFloat32

func (d *Decoder) DecodeFloat32() (float32, error)

DecodeFloat32 decodes an 'f' value into a float32.

func (*Decoder) DecodeFloat64

func (d *Decoder) DecodeFloat64() (float64, error)

DecodeFloat64 decodes an 'F' value into a float64.

func (*Decoder) DecodeHighPrecNumber

func (d *Decoder) DecodeHighPrecNumber() (string, error)

DecodeHighPrecNumber decodes an 'H' value into a string.

func (*Decoder) DecodeInt

func (d *Decoder) DecodeInt() (int, error)

DecodeInt decodes an integer value (U,i,I,l,L) into an int.

func (*Decoder) DecodeInt16

func (d *Decoder) DecodeInt16() (int16, error)

DecodeInt16 decodes an 'I' value into an int16.

func (*Decoder) DecodeInt32

func (d *Decoder) DecodeInt32() (int32, error)

DecodeInt32 decodes an 'l' value into an int32.

func (*Decoder) DecodeInt64

func (d *Decoder) DecodeInt64() (int64, error)

DecodeInt64 decodes an 'L' value into an int64.

func (*Decoder) DecodeInt8

func (d *Decoder) DecodeInt8() (int8, error)

DecodeInt8 decodes an 'i' value into an int8.

func (*Decoder) DecodeObject

func (d *Decoder) DecodeObject(decodeData func(*ObjectDecoder) error) error

DecodeObject decodes an object container.

func (*Decoder) DecodeString

func (d *Decoder) DecodeString() (string, error)

DecodeString decodes an 'S' value into a string.

func (*Decoder) DecodeUInt8

func (d *Decoder) DecodeUInt8() (uint8, error)

DecodeUInt8 decodes a 'U' value into a uint8.

func (*Decoder) DecodeValue

func (d *Decoder) DecodeValue(v Value) error

DecodeValue decodes the next value into v.

func (*Decoder) Object

func (d *Decoder) Object() (*ObjectDecoder, error)

Object begins decoding an object, and returns a specialized decoder for object entries.

type Encoder

type Encoder struct {
	// contains filtered or unexported fields
}

Encoder provides methods for encoding UBJSON data types.

func NewBlockEncoder

func NewBlockEncoder(w io.Writer) *Encoder

NewBlockEncoder returns a new block-notation Encoder.

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

NewEncoder returns a new Encoder.

func (*Encoder) Array

func (e *Encoder) Array() (*ArrayEncoder, error)

Array method encoding an array container.

func (*Encoder) ArrayLen

func (e *Encoder) ArrayLen(len int) (*ArrayEncoder, error)

ArrayLen begins encoding an array container with a specified length.

func (*Encoder) ArrayType

func (e *Encoder) ArrayType(elemType Marker, len int) (*ArrayEncoder, error)

ArrayType begins encoding a strongly-typed array container with a specified length. When encoding a single byte element type, actual elements are optimized away, and End() must be called immediately.

func (*Encoder) Encode

func (e *Encoder) Encode(v interface{}) error

Encode encodes v into universal binary json. Types implementing Value will be encoded via their MarshalUBJSON method.

func (*Encoder) EncodeArray

func (e *Encoder) EncodeArray(encodeData func(*Encoder) error) error

EncodeArray encodes an array container.

func (*Encoder) EncodeBool

func (e *Encoder) EncodeBool(v bool) error

EncodeBool encodes the true (T) or false (F) Marker.

func (*Encoder) EncodeChar

func (e *Encoder) EncodeChar(v byte) error

EncodeChar encodes a byte as a 'C'.

func (*Encoder) EncodeFloat32

func (e *Encoder) EncodeFloat32(v float32) error

EncodeFloat32 encodes a float32 as an 'f'.

func (*Encoder) EncodeFloat64

func (e *Encoder) EncodeFloat64(v float64) error

EncodeFloat64 encodes a float64 as an 'F'.

func (*Encoder) EncodeHighPrecNum

func (e *Encoder) EncodeHighPrecNum(v string) error

EncodeHighPrecNum encodes a string v as a high precision number 'H'.

func (*Encoder) EncodeInt

func (e *Encoder) EncodeInt(v int) error

EncodeInt encodes an int in the smallest possible integer format (U,i,L,l,L).

func (*Encoder) EncodeInt16

func (e *Encoder) EncodeInt16(v int16) error

EncodeInt16 encodes an int16 as an 'I'.

func (*Encoder) EncodeInt32

func (e *Encoder) EncodeInt32(v int32) error

EncodeInt32 encodes an int32 as an 'l'.

func (*Encoder) EncodeInt64

func (e *Encoder) EncodeInt64(v int64) error

EncodeInt64 encodes an int64 as an 'L'.

func (*Encoder) EncodeInt8

func (e *Encoder) EncodeInt8(v int8) error

EncodeInt8 encodes an int8 as an 'i'.

func (*Encoder) EncodeNoOp

func (e *Encoder) EncodeNoOp() error

EncodeNoOp encodes the NoOp valType.

func (*Encoder) EncodeNull

func (e *Encoder) EncodeNull() error

EncodeNull encodes the null valType.

func (*Encoder) EncodeObject

func (e *Encoder) EncodeObject(encodeData func(*Encoder) error) error

EncodeObject encodes an object container.

func (*Encoder) EncodeString

func (e *Encoder) EncodeString(v string) error

EncodeString encodes a string as a 'S'.

func (*Encoder) EncodeUInt8

func (e *Encoder) EncodeUInt8(v uint8) error

EncodeUInt8 encodes a uint8 as a (U).

func (*Encoder) EncodeValue

func (e *Encoder) EncodeValue(v Value) error

EncodeValue encodes the Value v, using UBJSONType and UnmarshalUBJSON.

func (*Encoder) Object

func (e *Encoder) Object() (*ObjectEncoder, error)

Object begins encoding an object container.

func (*Encoder) ObjectLen

func (e *Encoder) ObjectLen(len int) (*ObjectEncoder, error)

ObjectLen begins encoding an object container with a specified length.

func (*Encoder) ObjectType

func (e *Encoder) ObjectType(valType Marker, len int) (*ObjectEncoder, error)

ObjectType begins encoding a strongly-typed object container with a specified length.

type HighPrecNumber

type HighPrecNumber string

A HighPrecNumber is a decimal string of arbitrary precision, which is encoded with 'H' instead of 'S'.

Example
package main

import (
	"fmt"

	"github.com/jmank88/ubjson"
)

func main() {
	number := "1234567890.657483921"
	if b, err := ubjson.MarshalBlock(number); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}

	hNumber := ubjson.HighPrecNumber(number)
	if b, err := ubjson.MarshalBlock(hNumber); err != nil {
		fmt.Println("error: " + err.Error())
	} else {
		fmt.Println(string(b))
	}

}
Output:

[S][U][20][1234567890.657483921]
[H][U][20][1234567890.657483921]

type Marker

type Marker byte

A Marker is a single byte UBJSON marker.

const (
	NullMarker Marker = 'Z'

	NoOpMarker Marker = 'N'

	TrueMarker  Marker = 'T'
	FalseMarker Marker = 'F'

	UInt8Marker Marker = 'U'

	Int8Marker  Marker = 'i'
	Int16Marker Marker = 'I'
	Int32Marker Marker = 'l'
	Int64Marker Marker = 'L'

	Float32Marker Marker = 'd'
	Float64Marker Marker = 'D'

	HighPrecNumMarker Marker = 'H'

	CharMarker   Marker = 'C'
	StringMarker Marker = 'S'
)

Value Type Markers

const (
	ArrayStartMarker  Marker = '['
	ObjectStartMarker Marker = '{'
)

Container Types Markers

func (Marker) String

func (m Marker) String() string

type ObjectDecoder

type ObjectDecoder struct {
	Decoder
	// Value type, or 0 if none included.
	ValType Marker
	// Number of entries, or -1 if unspecified.
	Len int
	// contains filtered or unexported fields
}

An ObjectDecoder supplements a Decoder with NextEntry(), DecodeKey(), and End() methods. Callers must alternate decoding keys and values for either Len entries or until NextEntry() returns false, and finish with End().

func (*ObjectDecoder) DecodeKey

func (o *ObjectDecoder) DecodeKey() (string, error)

DecodeKey reads an object key.

func (*ObjectDecoder) End

func (o *ObjectDecoder) End() error

End completes object decoding and must be called. It may return errors (1) deferred from entry decoding, (2) from a missing object end marker, or (3) from a length vs. count mismatch.

func (*ObjectDecoder) NextEntry

func (o *ObjectDecoder) NextEntry() bool

NextEntry returns true if more entries are expected, or false if the end has been reached or an error was encountered, in which case End() will return the deferred error.

type ObjectEncoder

type ObjectEncoder struct {
	Encoder
	// contains filtered or unexported fields
}

An ObjectEncoder supplements an Encoder with EncodeKey() and End() methods, and performs validation and optimization of object Values. Callers must alternate Key() and Encode*() methods for the specified number of entries and finish with End().

func (*ObjectEncoder) EncodeKey

func (o *ObjectEncoder) EncodeKey(key string) error

EncodeKey encodes an object key.

func (*ObjectEncoder) End

func (o *ObjectEncoder) End() error

End checks the length or writes an end maker.

type Value

type Value interface {
	// The type marker for this kind of value. Must always return the same value.
	UBJSONType() Marker
	// Marshals the value to an encoder using containers and primitive values.
	MarshalUBJSON(*Encoder) error
	// Unmarshals containers and primitive values from a decoder into the value.
	UnmarshalUBJSON(*Decoder) error
}

The Value interface defines a custom encoding.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL