cbor

package
v0.0.0-...-13fba11 Latest Latest
Warning

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

Go to latest
Published: Nov 19, 2024 License: Apache-2.0 Imports: 13 Imported by: 5

Documentation

Overview

Package cbor implements a basic encoding/decoding API for RFC 8949 Concise Binary Object Representation (CBOR).

Not supported:

  • Indefinite length arrays, maps, byte strings, or text strings
  • Simple values other than bool, null, and undefined
  • Numbers greater than 64 bits
  • Decoding structs with more than one omittable field
  • Encoding/decoding structs to/from CBOR maps
  • Decoding CBOR maps with array/map/uncomparable keys to Go maps
  • Floats (yet)
  • UTF-8 validation of strings

However, the Marshaler/Unmarshaler interfaces allow any determinate sized CBOR item to be encoded to/from any Go type.

Specifically, >1 omittable struct fields (i.e. `omitempty`) is not supported, because handling this case is not generally solvable and depends on the specification of the API being implemented.

Encoding

Encoding can be done with [any] or Marshal. Using an Encoder may be more efficient when writing many items if a buffered writer is used. It also allows for setting encoding options.

var w bytes.Buffer
enc := cbor.NewEncoder(&w)

# Simple
_ = enc.Encode(true)        // true
_ = enc.Encode(false)       // false
_ = enc.Encode((*int)(nil)) // null

# Numbers
_ = enc.Encode(-1) // 0x20

// All encode to 0x01
_ = enc.Encode(int(1))
_ = enc.Encode(int8(1))
_ = enc.Encode(int16(1))
_ = enc.Encode(int32(1))
_ = enc.Encode(int64(1))
_ = enc.Encode(uint(1))
_ = enc.Encode(uint8(1))
_ = enc.Encode(uint16(1))
_ = enc.Encode(uint32(1))
_ = enc.Encode(uint64(1))

# Binary/Text
_ = enc.Encode([]byte{0x01, 0x02}) // 0x42 0x01 0x02
_ = enc.Encode("Hello World!")

# Homogeneous Arrays
_ = enc.Encode([]int{1, 2, 3})
_ = enc.Encode([][]byte{{0x01}, {0x02}, {0x03}})

# Heterogeneous Arrays (Tuples/Structs)
_ = enc.Encode(struct{ A int }{A: 1}) // 0x81, 0x01
_ = enc.Encode(struct{ A int; B string }{A: 1, B: "IETF"}) // 0x82, 0x01, 0x64, 0x49, 0x45, 0x54, 0x46

// Struct tags: change order by setting weights
_ = enc.Encode(struct{
	A int    `cbor:"1"`
	B string `cbor:"0"
}{
	A: 1,
	B: "IETF",
}) // 0x82, 0x64, 0x49, 0x45, 0x54, 0x46, 0x01

// Struct tags: ignore fields
_ = enc.Encode(struct{
	A int
	B string
	C bool `cbor:"-"`
}{
	A: 1,
	B: "IETF",
	C: true,
}) // 0x82, 0x01, 0x64, 0x49, 0x45, 0x54, 0x46

// Struct embedded fields
type Embed struct{ A int }
_ = enc.Encode(struct{
	Embed
	B string
}{
	Embed: Embed{A: 1},
	B:     "IETF",
}) // 0x82, 0x01, 0x64, 0x49, 0x45, 0x54, 0x46

# Maps
_ = enc.Encode(map[int]string{1: "hello"})
// Empty struct values also work (for sets)
_ = enc.Encode(map[int]struct{}{1: {}, 2: {}})
// Core deterministic encoding is used by default
_ = enc.Encode(map[int]struct{}{1: {}, 2: {}}, "hello": {}) // always ordered 1, 2, "hello"

# Tags
_ = enc.Encode(cbor.Tag[string]{Num: 42, Val: "Meaning of life"})
_ = enc.Encode(cbor.Tag[[]string]{Num: 42, Val: []string{"Meaning", "of", "life"}})

Decoding

Decoding can be done with Decoder.Decode or Unmarshal. Using a Decoder is generally more memory efficient than reading an entire io.Reader into a []byte and then unmarshaling it.

# Simple
var b bool
_ = cbor.Unmarshal([]byte{0xf4}, &b) // b = false
_ = cbor.Unmarshal([]byte{0xf5}, &b) // b = true
var i int
ip := &i
_ = cbor.Unmarshal([]byte{0xf6}, &ip) // ip = nil

# Numbers
var i8 int8
_ = cbor.Unmarshal([]byte{0x01}, &i8) // i8 = 1
_ = cbor.Unmarshal([]0byte{x20}, &i8) // i8 = -1

# Binary/Text
var bin []byte
_ = cbor.Unmarshal([]byte{0x45, 0x68, 0x65, 0x6c, 0x6c, 0x6f}, &bin) // bin = ['h', 'e', 'l', 'l', 'o']
var text string
_ = cbor.Unmarshal([]byte{0x65, 0x68, 0x65, 0x6c, 0x6c, 0x6f}, &text) // text = "hello"

# Homogeneous Arrays
var ints []int
_ = cbor.Unmarshal([]byte{0x85, 0x01, 0x02, 0x03, 0x04, 0x05}, &ints) // ints = [1, 2, 3, 4, 5]

# Heterogeneous Arrays (Tuples/Structs)
var s1 struct{ A int }
_ = cbor.Unmarshal([]byte{0x81, 0x01}, &s1) // s1 = {A: 1}
var s2 struct{ A int; B string }
_ = cbor.Unmarshal([]byte{0x82, 0x01, 0x64, 0x49, 0x45, 0x54, 0x46}, &s2) // s2 = {A: 1, B: "IETF"}

// Struct tags: change order by setting weights
var s3 struct{
	A int    `cbor:"1"`
	B string `cbor:"0"
}
_ = cbor.Unmarshal([]byte{0x82, 0x64, 0x49, 0x45, 0x54, 0x46, 0x01}, &s3) // s3 = {A: 1, B: "IETF"}

// Struct tags: ignore fields
var s4 struct{
	A int
	B string
	C bool `cbor:"-"`
}
_ = cbor.Unmarshal([]byte{0x82, 0x01, 0x64, 0x49, 0x45, 0x54, 0x46}, &s4) // s4 = {A: 1, B: "IETF", C: false}

// Struct tags: omit empty
var s5 struct{
	A int
	B string
	C bool `cbor:",omitempty"`
}
_ = cbor.Unmarshal([]byte{0x82, 0x01, 0x64, 0x49, 0x45, 0x54, 0x46}, &s5) // s5 = {A: 1, B: "IETF", C: false}

// Struct embedded fields
type Embed struct{ A int }
var s6 struct{
	Embed
	B string
}
_ = cbor.Unmarshal([]byte{0x82, 0x01, 0x64, 0x49, 0x45, 0x54, 0x46}, &s6) // s6 = {Embed: {A: 1}, B: "IETF"}

# Maps
var m1 map[int]int // m = nil
_ = cbor.Unmarshal([]byte{0xa0}, &m1) // m1 = {} <- non-nil!
_ = cbor.Unmarshal([]byte{0xa2, 0x01, 0x02, 0x03, 0x04}, &m1) // m1 = {1: 2, 3: 4}

# Tags
var tag cbor.Tag[string]
_ = cbor.Unmarshal([]byte{0xc1, 0x65, 0x68, 0x65, 0x6c, 0x6c, 0x6f}, &tag)
// tag = {Num: 1, Val: "hello"}

When decoding into an any/empty interface type, the following CBOR to Go type mapping is used:

Unsigned     -> int64
Negative     -> int64
Byte String  -> []byte
Text String  -> string
Array        -> []interface{}
Map          -> map[interface{}]interface{}
Tag          -> cbor.Tag[cbor.RawBytes]
Simple(Bool) -> bool

Decoding other types will fail, because it is not clear what memory to allocate. Even null cannot be decoded, because nil values still require a type in Go.

Index

Constants

View Source
const MaxArrayDecodeLength = 100_000

MaxArrayDecodeLength limits the max size of an array, string, byte slice, or map (where each key-value pair counts as two items).

Variables

This section is empty.

Functions

func BytewiseLexicalSort

func BytewiseLexicalSort(indices []int, keys [][]byte) func(i, j int) bool

BytewiseLexicalSort is a map key sorting function. It is the default for an `Encoder`.

It is the "new" canonical form whereas length-first is the "old" canonical form.

func Marshal

func Marshal(v any) ([]byte, error)

Marshal any type into CBOR.

func Unmarshal

func Unmarshal(data []byte, v any) error

Unmarshal any CBOR data. v must be a pointer type.

Types

type Bstr

type Bstr[T any] struct{ Val T }

Bstr marshals and unmarshals CBOR data that is a byte array of the CBOR encoding of its underlying value.

CDDL: bstr .cbor T

This is a common convention in specifications like COSE and FDO and acts as a sort of type erasure. While a specification may wish to erase a type to allow for operating on arbitrary data (i.e. payloads in COSE signature structures), implementations sometimes _do_ want to specify the encoded type.

This generic bstr structure conveys type information as well as handles automatically unmarshaling into the proper type. If type erasure is indeed desired, then use a type alias: `type bstr = cbor.Bstr[cbor.RawBytes]`.

func NewBstr

func NewBstr[T any](v T) *Bstr[T]

NewBstr is shorthand for struct initialization and is useful, because it often does not require writing the type parameter.

func (Bstr[T]) MarshalCBOR

func (b Bstr[T]) MarshalCBOR() ([]byte, error)

MarshalCBOR implements Marshaler.

func (*Bstr[T]) UnmarshalCBOR

func (b *Bstr[T]) UnmarshalCBOR(p []byte) error

UnmarshalCBOR implements Unmarshaler.

type ByteWrap

type ByteWrap[T any] struct{ Val T }

ByteWrap is a Bstr that treats Bstr[[]byte] as Bstr[cbor.RawBytes]. While Bstr guarantees that the inner bytes are valid CBOR, ByteWrap does not. ByteWrap only ensures that the marshaled type is a bytestring.

In other words, it avoids double-encoding a byte string. This convention is used in COSE.

func NewByteWrap

func NewByteWrap[T any](v T) *ByteWrap[T]

NewByteWrap is shorthand for struct initialization and is useful, because it often does not require writing the type parameter.

func (ByteWrap[T]) MarshalCBOR

func (b ByteWrap[T]) MarshalCBOR() ([]byte, error)

MarshalCBOR implements Marshaler.

func (*ByteWrap[T]) UnmarshalCBOR

func (b *ByteWrap[T]) UnmarshalCBOR(p []byte) error

UnmarshalCBOR implements Unmarshaler.

type Decoder

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

Decoder iteratively consumes a reader, decoding CBOR types.

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder returns a new Decoder. The io.Reader is not copied.

func (*Decoder) Decode

func (d *Decoder) Decode(v any) error

Decode a single CBOR item from the internal io.Reader.

type Encoder

type Encoder struct {

	// MapKeySort is used to determine sort order of map keys for encoding. If
	// none is set, then Core Deterministic (bytewise lexical) encoding is
	// used.
	//
	// The provided function is called with indices 0..len(keys)-1 and
	// marshaled map keys in a random order. The return value is expected to be
	// a "less" function that is used to iteratively sort the indices in place
	// while the marshaled keys remain unmodified.
	MapKeySort func(indices []int, marshaledKeys [][]byte) func(i, j int) bool
	// contains filtered or unexported fields
}

Encoder allows for setting encoding options when marshaling CBOR data.

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

NewEncoder returns a new Encoder. The io.Writer is not automatically flushed.

func (*Encoder) Encode

func (e *Encoder) Encode(v any) error

Encode CBOR data to the underlying io.Writer.

type ErrUnsupportedType

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

ErrUnsupportedType means that a value of this type cannot be encoded.

func (ErrUnsupportedType) Error

func (e ErrUnsupportedType) Error() string

type FlatMarshaler

type FlatMarshaler interface {
	// FlatMarshalCBOR encodes CBOR objects to a stream (not wrapped in a CBOR
	// array). The number of objects decoded must match the flatN option of the
	// cbor tag.
	FlatMarshalCBOR(io.Writer) error
}

FlatMarshaler is implemented by types to provide more than one object of an array. This is particularly useful in structs to match the behavior of embedded struct fields, but with full control, like Marshaler.

FlatMarshaler is used iff the field has a flatN cbor struct tag, i.e. `cbor:",flat2"`.

type FlatUnmarshaler

type FlatUnmarshaler interface {
	// FlatUnmarshalCBOR decodes CBOR objects from a stream (not an array). The
	// number of objects decoded must match the flatN option of the cbor tag.
	FlatUnmarshalCBOR(io.Reader) error
}

FlatUnmarshaler is implemented by types to consume more than one object of an array. This is particularly useful in structs to match the behavior of embedded struct fields, but with full control, like Unmarshaler.

FlatUnmarshaler is used iff the field has a flatN cbor struct tag, i.e. `cbor:",flat2"`.

type Marshaler

type Marshaler interface {
	MarshalCBOR() ([]byte, error)
}

Marshaler is the interface implemented by types that can marshal themselves into valid CBOR.

type OmitEmpty

type OmitEmpty[T any] struct{ Val T }

OmitEmpty encodes a zero value (zero, empty array, empty byte string, empty string, empty map) as zero bytes.

func (OmitEmpty[T]) MarshalCBOR

func (o OmitEmpty[T]) MarshalCBOR() ([]byte, error)

MarshalCBOR encodes a zero value (zero, empty array, empty byte string, empty string, empty map) as zero bytes.

func (*OmitEmpty[T]) UnmarshalCBOR

func (o *OmitEmpty[T]) UnmarshalCBOR(p []byte) error

UnmarshalCBOR decodes data into its generic typed Val field. Note that OmitEmpty is treated specially by the cbor package such that reading zero bytes (EOF) will not cause an error.

type RawBytes

type RawBytes []byte

RawBytes encodes and decodes untransformed. When encoding, it must contain valid CBOR.

func (RawBytes) MarshalCBOR

func (b RawBytes) MarshalCBOR() ([]byte, error)

MarshalCBOR implements Marshaler.

func (*RawBytes) UnmarshalCBOR

func (b *RawBytes) UnmarshalCBOR(p []byte) error

UnmarshalCBOR implements Unmarshaler.

type Tag

type Tag[T any] struct {
	Num uint64 // 0..(2**64)-1
	Val T
}

Tag is a tagged CBOR type.

func (Tag[T]) Number

func (t Tag[T]) Number() uint64

Number returns the underlying Num field and is used to implement the TagData interface.

func (Tag[T]) Value

func (t Tag[T]) Value() any

Value returns the underlying Val field and is used to implement the TagData interface.

type TagData

type TagData interface {
	Number() uint64
	Value() any
	// contains filtered or unexported methods
}

TagData allows read-only access to a Tag without value type information.

type Timestamp

type Timestamp time.Time

Timestamp implements the timestamp CBOR format used in the FDO error message type. The expected string format, if used, is RFC3339.

timestamp = null / UTCStr / UTCInt / TIME_T
UTCStr = #6.0(tstr)
UTCInt = #6.1(uint)
TIMET  = #6.1(uint)

func (Timestamp) MarshalCBOR

func (ts Timestamp) MarshalCBOR() ([]byte, error)

MarshalCBOR implements Marshaler.

func (*Timestamp) UnmarshalCBOR

func (ts *Timestamp) UnmarshalCBOR(data []byte) error

UnmarshalCBOR implements Unmarshaler.

type Unmarshaler

type Unmarshaler interface {
	UnmarshalCBOR([]byte) error
}

Unmarshaler is the interface implemented by types that can unmarshal a CBOR description of themselves. The data is invalid upon the function returning.

type X509Certificate

type X509Certificate x509.Certificate

X509Certificate is a newtype for x509.Certificate implementing proper CBOR encoding.

func (*X509Certificate) MarshalCBOR

func (c *X509Certificate) MarshalCBOR() ([]byte, error)

MarshalCBOR implements Marshaler interface.

func (*X509Certificate) UnmarshalCBOR

func (c *X509Certificate) UnmarshalCBOR(data []byte) error

UnmarshalCBOR implements Unmarshaler interface.

type X509CertificateRequest

type X509CertificateRequest x509.CertificateRequest

X509CertificateRequest is a newtype for x509.CertificateRequest implementing proper CBOR encoding.

func (X509CertificateRequest) MarshalCBOR

func (c X509CertificateRequest) MarshalCBOR() ([]byte, error)

MarshalCBOR implements Marshaler interface.

func (*X509CertificateRequest) UnmarshalCBOR

func (c *X509CertificateRequest) UnmarshalCBOR(data []byte) error

UnmarshalCBOR implements Unmarshaler interface.

Directories

Path Synopsis
Package cdn implements CBOR Diagnotic Notation.
Package cdn implements CBOR Diagnotic Notation.

Jump to

Keyboard shortcuts

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