cbor

package module
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2026 License: MIT Imports: 16 Imported by: 0

README

go-cbor

A zero-dependency CBOR (RFC 8949 / STD 94) codec for Go, with an API that mirrors encoding/json. Deterministic (canonical) encoding by default — ready for COSE, CWT, and ISO mdoc/VICAL signing without configuration. Round-trips the RFC 8949 Appendix A test vectors, is fuzzed (round-trip and streaming), and never panics on malformed input.

import cbor "github.com/MichaelFraser99/go-cbor"

Quick start

b, _ := cbor.Marshal(map[string]int{"a": 1}) // canonical CBOR bytes
var v map[string]int
_ = cbor.Unmarshal(b, &v)

Marshal / Unmarshal / Valid behave like their encoding/json counterparts.

Struct tags

type Header struct {
    Alg int    `cbor:"1,asint"`           // integer map key (COSE label)
    Kid []byte `cbor:"4,asint,omitempty"`
}
type Sign1 struct {
    _         struct{} `cbor:",toarray"`      // encode struct as an array, not a map
    Protected []byte
    Payload   []byte
    Signature []byte
}
Tag option Effect
cbor:"name" field key is the text string name
cbor:"1,asint" field key is the integer 1
cbor:"-" field is skipped
,omitempty omit when the field is its zero value
,omitzero omit when the field IsZero()
,toarray on _ struct{} encode the whole struct as a positional array

Coming from encoding/json? Same API shape, CBOR semantics — the differences that bite:

  • Decode matches field names case-sensitively (json doesn't).
  • Use ,omitzero, not ,omitempty, for time.Time and structsomitempty never omits a struct, so a zero time.Time encodes as its year-1 sentinel.
  • any decodes to cbor.Map (ordered), not map[string]any — use Map.ToStringMap() or a concrete type.
  • Use cbor.RawMessage (json.RawMessage isn't special). Embedded structs follow json's rules: untagged flattened, tagged nested, shallowest-wins.

Type mapping

Marshal (Go → CBOR)

Go CBOR
bool, nil true/false, null
nil slice / nil map / nil pointer null
int*, uint* integer (shortest form)
float32/64 float (shortest width)
string / []byte text / byte string
slice, array array
map, struct map (or array with toarray)
*big.Int integer or bignum tag
time.Time tag 1 epoch (or tag 0 text via options)
Marshaler whatever MarshalCBOR returns
RawMessage, Tag, RawTag, SimpleValue, Undefined, DataItem, Map, EncodedCBOR as described

Unmarshal into any yields native values: int64 (or uint64 / *big.Int at the 64-bit extremes; bignum tags 2/3 also yield *big.Int), float64, string, []byte, bool, nil, []any, cbor.Map (ordered key/value list), cbor.Tag, cbor.SimpleValue, cbor.Undefined{} (for the undefined value). Decode into a concrete map[K]V when you know the schema and want O(1) lookup; into *cbor.Map for the ordered map directly (Map.ToStringMap() converts to map[string]any when keys are strings); into *cbor.DataItem for the loss-free tree; into *cbor.RawMessage for exact bytes; into *cbor.RawTag to capture a tag's content verbatim (e.g. a COSE protected header a verifier must hash as received).

var v any
_ = cbor.Unmarshal(data, &v)
m := v.(cbor.Map)             // for a CBOR map
val, ok := m.Get(int64(1))    // keys match by exact Go type: int64, not int
n, ok := m.GetInt(int64(1))   // typed getters: GetInt/GetUint/GetFloat/GetBool/
                              // GetString/GetBytes/GetSlice/GetMap/GetTag.
                              // GetInt/GetUint coerce across int64/uint64/*big.Int.

Options

Immutable, reusable, goroutine-safe modes:

em, _ := cbor.EncoderOptions{Sort: cbor.SortLengthFirst}.Encoding()
b, _ := em.Marshal(v)
EncoderOptions Values (default first)
Sort SortBytewise, SortLengthFirst, SortNone
Time TimeUnix, TimeRFC3339, TimeNumericDate (untagged epoch, for CWT/JWT)
Float FloatShortest, FloatDouble
NaN NaN7e00, NaNNone
BigInt BigIntShortest, BigIntTag
DecoderOptions Meaning
MaxNestingDepth container-nesting cap (default 1024)
DuplicateKeys DupAllow, DupError
Strict reject non-shortest / non-minimal encodings and unsorted keys (but not indefinite — see below)
RejectIndefinite reject indefinite-length items
MaxArrayLen / MaxMapLen element caps (0 = unlimited)
MaxStringLength per-string byte cap (0 = unlimited)

Two presets return a ready-made DecoderOptions:

  • UntrustedDecoderOptions() — hardened for attacker input (caps + dup-key + no indefinite).
  • CanonicalDecoderOptions() — rejects anything not in RFC 8949 §4.2.1 canonical form (non-shortest, non-minimal bignums, unsorted keys, indefinite, duplicate keys) for the verify side of COSE/CWT/mdoc. Note Strict alone does not reject indefinite-length items, which is why this preset also sets RejectIndefinite.

Untrusted input

dm, _ := cbor.UntrustedDecoderOptions().Decoding() // depth + dup-key + element/string caps + no indefinite
err := dm.Unmarshal(networkBytes, &v)

// Streaming from a connection: wrap the reader so total input is bounded too.
sd, _ := cbor.UntrustedDecoderOptions().NewDecoder(io.LimitReader(conn, 1<<20))

The default decoder is bounds-checked and never panics, but by default accepts duplicate keys, non-canonical encodings, and indefinite-length items; UntrustedDecoderOptions tightens all of these and adds element, pair, and per-string (1 MiB) caps. It rejects indefinite-length items deliberately — their streaming form otherwise sidesteps the element and duplicate-key caps. It is not a substitute for bounding total request size; pair it with an io.LimitReader / http.MaxBytesReader — especially with the streaming Decoder, whose default (unconfigured) form will buffer a hostile declared string length without limit.

Streaming

enc := cbor.NewEncoder(w) // enc.Encode(x) per item
dec := cbor.NewDecoder(r) // dec.Decode(&x) until io.EOF

Decode reads only as many bytes as each item needs, so it works on a connection that stays open between items — it returns as soon as one complete item has arrived rather than waiting for EOF. A truncated final item returns io.ErrUnexpectedEOF. Encoder reuses its buffer (no per-item allocation); Decoder.InputOffset() and Decoder.Buffered() support connection hand-off to another protocol.

Inspecting

s, _ := cbor.Diagnostic(data) // CBOR diagnostic notation, e.g. {1: [1, 2, 3]}

See the runnable examples for COSE-style headers, toarray, streaming, RawMessage, and more.

Documentation

Overview

Package cbor implements encoding and decoding of CBOR (Concise Binary Object Representation, RFC 8949 / STD 94) with an API that mirrors encoding/json.

Quick start

b, _ := cbor.Marshal(map[string]int{"a": 1}) // deterministic CBOR bytes
var v map[string]int
_ = cbor.Unmarshal(b, &v)

Marshal produces deterministic (canonical) CBOR by default, per RFC 8949 §4.2.1: shortest-form integers and floats, and map keys sorted by the bytewise lexicographic order of their encodings. COSE, CWT and ISO mdoc all require this, so nothing needs configuring for signing or hashing.

Struct tags

Fields use cbor:"..." tags, like encoding/json, with CBOR-specific extras:

type Header struct {
    Alg int    `cbor:"1,asint"`           // integer map key (e.g. COSE labels)
    Kid []byte `cbor:"4,asint,omitempty"`
}

type Sign1 struct {
    _         struct{} `cbor:",toarray"`      // encode as an array, not a map
    Protected []byte
    Payload   []byte
    Signature []byte
}

Recognised options: a name (or an integer with asint), "-" to skip a field, "omitempty", "omitzero", and ",toarray" on a blank _ field to encode the whole struct as a positional array.

The API shape mirrors encoding/json, but the semantics are CBOR's, not JSON's. In particular: only cbor:"..." tags are read (json:"..." tags, including json:"-", are ignored); untagged fields use the Go field name; and field-name matching on decode is case-sensitive (unlike encoding/json). Embedded (anonymous) struct fields follow encoding/json's rules — an untagged embedded struct's fields are promoted to the parent, an embedded field with a tag is nested under that name, and name conflicts resolve by the same shallowest-wins, tagged-beats-untagged, ties-dropped rules. Prefer omitzero over omitempty for time.Time and other struct types: omitempty tests a zero value and never omits a struct, so a zero time.Time is emitted as its year-1 sentinel rather than dropped.

Type mapping

Marshal: bool→true/false, nil→null, int/uint→major 0/1, float32/64→shortest float, string→text string, []byte→byte string, slice/array→array, map/struct→map (or array with toarray), *big.Int→integer or bignum tag, time.Time→tag 1 epoch (or tag 0 text, or a bare untagged epoch, via TimeMode). A nil slice, nil map, or nil pointer encodes to null. Types implementing Marshaler encode themselves.

Unmarshal into a concrete Go type is the reverse. Unmarshal into an any yields native values: int64 (or uint64 / *big.Int at the 64-bit extremes; bignum tags 2 and 3 also yield *big.Int), float64, string, []byte, bool, nil, []any, Map (an ordered key/value list), Tag, SimpleValue and Undefined. Unmarshal into a *DataItem yields the loss-free tree; into a *RawMessage captures the item's exact bytes undecoded; into a *RawTag captures a tag's content verbatim; into a *Map yields the ordered map directly. A bare (untagged) number also decodes into a time.Time (RFC 8392 / RFC 7519 NumericDate).

Options

Encoding and decoding are configured through immutable, reusable, goroutine- safe modes:

em, _ := cbor.EncoderOptions{Sort: cbor.SortLengthFirst}.Encoding()
b, _ := em.Marshal(v)

dm, _ := cbor.UntrustedDecoderOptions().Decoding() // safe limits for untrusted input
err := dm.Unmarshal(data, &v)

See EncoderOptions (sort order, float/NaN/bignum form, time format) and DecoderOptions (nesting depth, duplicate keys, element caps, strict canonical validation, indefinite-length rejection).

Streaming

NewEncoder and NewDecoder write and read a sequence of items; Decoder.Decode returns io.EOF at the end of the stream.

Inspecting

Diagnostic renders bytes in CBOR diagnostic notation (RFC 8949 §8), and DataItem.MarshalJSON gives a JSON view for debugging.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Diagnostic

func Diagnostic(data []byte) (string, error)

Diagnostic renders one CBOR item as CBOR diagnostic notation (RFC 8949 §8): e.g. [1, 2, 3], {1: 2}, h'01ff', "text", 0("2013-…"), true, NaN. Unlike the JSON view it distinguishes byte strings from text strings and shows tag numbers.

Example
package main

import (
	"fmt"

	cbor "github.com/MichaelFraser99/go-cbor"
)

func main() {
	s, _ := cbor.Diagnostic([]byte{0xa1, 0x01, 0x83, 0x01, 0x02, 0x03})
	fmt.Println(s)
}
Output:
{1: [1, 2, 3]}

func Marshal

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

Marshal returns the deterministic (canonical, RFC 8949 §4.2.1) CBOR encoding of v. See the package overview for the Go-to-CBOR type mapping and struct tags, and EncoderOptions for non-default encoding.

Example
package main

import (
	"fmt"

	cbor "github.com/MichaelFraser99/go-cbor"
)

func main() {
	b, _ := cbor.Marshal(map[string]int{"a": 1, "b": 2})
	fmt.Printf("%x\n", b)
}
Output:
a2616101616202
Example (StructTags)
package main

import (
	"fmt"

	cbor "github.com/MichaelFraser99/go-cbor"
)

func main() {
	type Header struct {
		Alg int    `cbor:"1,asint"`
		Kid []byte `cbor:"4,asint,omitempty"`
	}
	b, _ := cbor.Marshal(Header{Alg: -7}) // {1: -7}, Kid omitted
	fmt.Printf("%x\n", b)
}
Output:
a10126
Example (Toarray)
package main

import (
	"fmt"

	cbor "github.com/MichaelFraser99/go-cbor"
)

func main() {
	type Pair struct {
		_ struct{} `cbor:",toarray"`
		A int
		B int
	}
	b, _ := cbor.Marshal(Pair{A: 1, B: 2}) // encodes as [1, 2]
	fmt.Printf("%x\n", b)
}
Output:
820102

func Unmarshal

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

Unmarshal parses one CBOR item from data and stores it in the value pointed to by v, which must be a non-nil pointer. v may be a pointer to a concrete Go type, to an any (yielding native values, with maps as a Map), to a DataItem (the loss-free tree), or to a RawMessage (the item's exact bytes). It is an error for data to contain trailing bytes after the item; use a Decoder for a sequence.

When a tagged item is decoded into a concrete (non-Tag) type, the tag is unwrapped and its number is not checked. Decode into a Tag or an any if the tag's identity is significant — for example the COSE message type carried by tag 18 vs 17.

Example
package main

import (
	"fmt"

	cbor "github.com/MichaelFraser99/go-cbor"
)

func main() {
	data := []byte{0xa2, 0x61, 0x61, 0x01, 0x61, 0x62, 0x02}
	var m map[string]int
	_ = cbor.Unmarshal(data, &m)
	fmt.Println(m["a"], m["b"])
}
Output:
1 2

func Valid

func Valid(data []byte) error

Valid reports whether data is exactly one well-formed CBOR item with no trailing bytes, returning a *SyntaxError otherwise.

Types

type BigIntMode

type BigIntMode uint8

BigIntMode controls how *big.Int values are encoded.

const (
	// BigIntShortest uses a plain integer when the value fits, else a bignum tag.
	BigIntShortest BigIntMode = iota
	// BigIntTag always uses a bignum tag (2 or 3).
	BigIntTag
)

type DataItem

type DataItem struct {
	// Major is the item's major type.
	Major MajorType

	// Argument holds the head argument: the value for MajorUint/MajorNint, the
	// tag number for MajorTag, or the simple value for MajorOther when
	// FloatWidth is 0.
	Argument uint64

	// Float and FloatWidth apply when Major is MajorOther and FloatWidth is
	// non-zero; FloatWidth is the encoded width in bytes (2, 4, or 8).
	Float      float64
	FloatWidth uint8

	// Bytes holds a byte string (MajorBytes) or a text string's UTF-8 bytes
	// (MajorText).
	Bytes []byte

	// Content holds child items: a tag's single item, an array's elements, or a
	// map's flattened key, value, key, value… sequence.
	Content []*DataItem
}

DataItem is the loss-free, fully-typed representation of one decoded CBOR item. Unmarshal populates it when the target is a *DataItem, and Marshal re-encodes it. Its fields are interpreted by Major (see the MajorType constants). Build one directly or with the constructor helpers (Uint, ArrayOf, TagOf, …), and use Native to convert it to ordinary Go values.

func ArrayOf

func ArrayOf(items ...*DataItem) *DataItem

ArrayOf builds an array data item from the given elements.

Example
package main

import (
	"fmt"

	cbor "github.com/MichaelFraser99/go-cbor"
)

func main() {
	item := cbor.ArrayOf(cbor.Uint(1), cbor.Text("hi"), cbor.TagOf(0, cbor.Text("t")))
	b, _ := cbor.Marshal(item)
	fmt.Printf("%x\n", b)
}
Output:
8301626869c06174

func Bool

func Bool(b bool) *DataItem

Bool builds a boolean simple-value data item.

func ByteString

func ByteString(b []byte) *DataItem

ByteString builds a byte-string data item.

func Float

func Float(f float64) *DataItem

Float builds a double-precision (8-byte) float data item. It does not select the shortest width; set FloatWidth yourself, or encode via the reflect path (a plain float64), for canonical shortest-form floats.

func Int

func Int(i int64) *DataItem

Int builds an integer data item from a signed value.

func MapOf

func MapOf(pairs ...*DataItem) *DataItem

MapOf builds a map data item from a flat key, value, key, value… sequence.

func Nint

func Nint(n uint64) *DataItem

Nint builds a negative-integer data item whose value is -1 - n (so Nint(0) is -1 and Nint(6) is -7). For a signed value, prefer Int.

func Null

func Null() *DataItem

Null builds the null simple value.

func Simple

func Simple(v byte) *DataItem

Simple builds a simple value (0–19 or 32–255).

func TagOf

func TagOf(number uint64, content *DataItem) *DataItem

TagOf wraps content in a tag with the given number.

func Text

func Text(s string) *DataItem

Text builds a text-string data item.

func Uint

func Uint(n uint64) *DataItem

Uint builds an unsigned-integer data item.

func (DataItem) MarshalJSON

func (d DataItem) MarshalJSON() ([]byte, error)

MarshalJSON renders the item as a JSON debugging view of the form {"majorType":N,"data":…}; it is not the CBOR codec. For CBOR diagnostic notation, use Diagnostic. Conventions: byte strings are base64url (no padding); integers outside ±(2^53-1) and bignums are emitted as strings to avoid JSON precision loss; NaN, Infinity, -Infinity and undefined are emitted as the strings "NaN"/"Infinity"/"-Infinity"/"undefined" (JSON has no literal for them), so use the majorType field to disambiguate them from genuine text strings.

func (DataItem) Native

func (d DataItem) Native() any

Native converts the item to ordinary Go values: int64/uint64/*big.Int, float64, string, []byte, bool, nil, []any, Map, Tag, and SimpleValue.

type Decoder

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

Decoder reads a sequence of CBOR items from an io.Reader. It reads only as many bytes as each item requires, so it is suitable for streaming from a connection that stays open between items: Decode returns as soon as one complete item has arrived rather than waiting for the reader to reach EOF.

func NewDecoder

func NewDecoder(r io.Reader) *Decoder

NewDecoder returns a Decoder that reads from r with default decoding. Use DecoderOptions.NewDecoder to configure it.

func (*Decoder) Buffered

func (d *Decoder) Buffered() io.Reader

Buffered returns a reader over bytes read from the underlying reader but not yet consumed by Decode. Use it to hand a connection to another protocol after reading a known number of CBOR items.

func (*Decoder) Decode

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

Decode reads the next CBOR item from the stream into v, returning io.EOF once the stream is exhausted. It reads exactly enough bytes to frame one item, so a reader that stays open after the item does not block the call. A truncated final item returns io.ErrUnexpectedEOF. A malformed item is a terminal condition: the error recurs on each subsequent call rather than resyncing into the garbage, so treat a non-EOF error as the end of the stream and stop reading. A Decoder is not safe for concurrent use.

func (*Decoder) InputOffset

func (d *Decoder) InputOffset() int64

InputOffset returns the number of bytes consumed from the stream so far — the position at which the next item begins.

type DecoderOptions

type DecoderOptions struct {
	// MaxNestingDepth bounds container nesting; <= 0 uses the default (1024).
	MaxNestingDepth int
	// DuplicateKeys selects the duplicate-key policy.
	DuplicateKeys DupMode
	// Strict rejects non-shortest integer/float encodings, non-minimal bignums,
	// and unsorted map keys.
	Strict bool
	// RejectIndefinite rejects indefinite-length items.
	RejectIndefinite bool
	// MaxArrayLen bounds an array's element count; 0 means unlimited.
	MaxArrayLen int
	// MaxMapLen bounds a map's key/value pair count; 0 means unlimited.
	MaxMapLen int
	// MaxStringLength bounds the byte length of any single byte or text string
	// (and of a bignum's byte string); 0 means unlimited.
	MaxStringLength int
}

DecoderOptions configures a Decoding. The zero value matches the default Unmarshal (a 1024 nesting-depth cap, otherwise permissive). See UntrustedDecoderOptions for a hardened preset.

func CanonicalDecoderOptions

func CanonicalDecoderOptions() DecoderOptions

CanonicalDecoderOptions returns a preset that rejects any input not in RFC 8949 §4.2.1 deterministic (canonical) form: non-shortest integers/floats, non-minimal bignums, unsorted map keys, indefinite-length items, and duplicate map keys. Use it on the verify side of COSE/CWT/mdoc, where accepting a non-canonical re-encoding of signed content is a hazard. Note that Strict alone does NOT reject indefinite-length items, which is why this preset sets RejectIndefinite too. It adds no size caps; combine with UntrustedDecoderOptions (or set the Max* fields) to also bound allocation.

func UntrustedDecoderOptions

func UntrustedDecoderOptions() DecoderOptions

UntrustedDecoderOptions returns a conservative preset for decoding untrusted input: a shallow nesting cap, duplicate-key rejection, element/pair caps, a per-string length cap (1 MiB), and rejection of indefinite-length items (whose streaming form otherwise sidesteps the element and duplicate-key caps). It is not a substitute for bounding the total input size. Adjust the returned value before calling Decoding if the limits don't fit your data — for example, raise MaxStringLength for larger embedded blobs.

Example
package main

import (
	"fmt"

	cbor "github.com/MichaelFraser99/go-cbor"
)

func main() {
	dm, _ := cbor.UntrustedDecoderOptions().Decoding()
	err := dm.Valid([]byte{0xa2, 0x01, 0x01, 0x01, 0x02}) // {1:1, 1:2} duplicate key
	fmt.Println(err != nil)
}
Output:
true

func (DecoderOptions) Decoding

func (o DecoderOptions) Decoding() (Decoding, error)

Decoding builds an immutable Decoding from the options, or an error if any option value is out of range.

func (DecoderOptions) NewDecoder

func (o DecoderOptions) NewDecoder(r io.Reader) (*Decoder, error)

NewDecoder returns a Decoder reading from r with the configured options.

type Decoding

type Decoding interface {
	Unmarshal(data []byte, v any) error
	Valid(data []byte) error
}

Decoding is an immutable, reusable, goroutine-safe decoder configuration.

type DupMode

type DupMode uint8

DupMode controls the duplicate-map-key policy on decode.

const (
	// DupAllow keeps the last value for a duplicate key (default).
	DupAllow DupMode = iota
	// DupError rejects any map containing duplicate keys.
	DupError
)

type EncodedCBOR

type EncodedCBOR []byte

EncodedCBOR is an already-encoded CBOR data item carried as "embedded CBOR": a byte string wrapped in tag 24 (RFC 8949 §3.4.5.1). Marshal emits tag 24 around the bytes; Unmarshal expects tag 24 wrapping a byte string and stores a copy of its content. This is the common shape in COSE and ISO mdoc/VICAL (for example IssuerSignedItemBytes and MobileSecurityObjectBytes), where a structure is frozen as opaque bytes so it can be signed or hashed independently of re-encoding. An empty EncodedCBOR marshals to null.

Example
package main

import (
	"fmt"

	cbor "github.com/MichaelFraser99/go-cbor"
)

func main() {
	inner, _ := cbor.Marshal(map[int]int{1: 2})

	type Signed struct {
		Payload cbor.EncodedCBOR `cbor:"p"` // tag-24-wrapped embedded CBOR
	}
	b, _ := cbor.Marshal(Signed{Payload: inner})
	fmt.Printf("%x\n", b)

	var got Signed
	_ = cbor.Unmarshal(b, &got)
	fmt.Printf("%x\n", []byte(got.Payload))
}
Output:
a16170d81843a10102
a10102

func (EncodedCBOR) Decode

func (e EncodedCBOR) Decode(v any) error

Decode unmarshals the embedded item into v. The embedded bytes are captured verbatim and are NOT validated by UnmarshalCBOR, so Decode is where malformed embedded CBOR surfaces. For untrusted input, pass the EncodedCBOR to a configured Decoding.Unmarshal instead, so the decode limits apply to the embedded item too.

func (EncodedCBOR) MarshalCBOR

func (e EncodedCBOR) MarshalCBOR() ([]byte, error)

MarshalCBOR wraps the embedded item in tag 24, or emits null when empty.

func (*EncodedCBOR) UnmarshalCBOR

func (e *EncodedCBOR) UnmarshalCBOR(data []byte) error

UnmarshalCBOR stores a copy of the tag-24 byte string's content, or nil for null. It does not check that the content is well-formed CBOR — the bytes are captured verbatim so they can be signed or hashed as received; use Decode or Valid to check.

type Encoder

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

Encoder writes a sequence of CBOR items to an io.Writer. It reuses its encoding state and buffer across Encode calls, so a high-rate stream allocates nothing per item beyond what encoding the value itself requires.

func NewEncoder

func NewEncoder(w io.Writer) *Encoder

NewEncoder returns an Encoder that writes to w using the default (canonical) encoding. Use EncoderOptions.NewEncoder to configure it.

Example
package main

import (
	"bytes"
	"fmt"
	"io"

	cbor "github.com/MichaelFraser99/go-cbor"
)

func main() {
	var buf bytes.Buffer
	enc := cbor.NewEncoder(&buf)
	_ = enc.Encode(1)
	_ = enc.Encode("two")

	dec := cbor.NewDecoder(&buf)
	for {
		var v any
		if err := dec.Decode(&v); err == io.EOF {
			break
		}
		fmt.Println(v)
	}
}
Output:
1
two

func (*Encoder) Encode

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

Encode writes the CBOR encoding of v to the stream. Nothing is written if encoding v fails, so a failed item cannot corrupt the stream.

type EncoderOptions

type EncoderOptions struct {
	Sort   SortMode
	Time   TimeMode
	Float  FloatMode
	NaN    NaNMode
	BigInt BigIntMode
}

EncoderOptions configures an Encoding. The zero value is the canonical default used by Marshal.

Example
package main

import (
	"fmt"

	cbor "github.com/MichaelFraser99/go-cbor"
)

func main() {
	em, _ := cbor.EncoderOptions{Sort: cbor.SortLengthFirst}.Encoding()
	b, _ := em.Marshal(map[int]int{24: 1, -1: 2}) // shorter key (-1) first
	fmt.Printf("%x\n", b)
}
Output:
a22002181801

func (EncoderOptions) Encoding

func (o EncoderOptions) Encoding() (Encoding, error)

Encoding builds an immutable Encoding from the options, or an error if any option value is out of range.

func (EncoderOptions) NewEncoder

func (o EncoderOptions) NewEncoder(w io.Writer) (*Encoder, error)

NewEncoder returns an Encoder writing to w with the configured options.

type Encoding

type Encoding interface {
	Marshal(v any) ([]byte, error)
}

Encoding is an immutable, reusable, goroutine-safe encoder configuration.

type FloatMode

type FloatMode uint8

FloatMode controls float width selection.

const (
	// FloatShortest uses the smallest of 16/32/64 bits that preserves the value.
	FloatShortest FloatMode = iota
	// FloatDouble always encodes 64-bit doubles.
	FloatDouble
)

type InvalidUnmarshalError

type InvalidUnmarshalError struct {
	Type reflect.Type
}

InvalidUnmarshalError reports an invalid argument to Unmarshal; the argument must be a non-nil pointer.

func (*InvalidUnmarshalError) Error

func (e *InvalidUnmarshalError) Error() string

type MajorType

type MajorType uint8

MajorType is a CBOR major type (0–7), the top three bits of an item's initial byte.

const (
	MajorUint  MajorType = 0 // unsigned integer
	MajorNint  MajorType = 1 // negative integer (value is -1 - Argument)
	MajorBytes MajorType = 2 // byte string
	MajorText  MajorType = 3 // UTF-8 text string
	MajorArray MajorType = 4 // array
	MajorMap   MajorType = 5 // map
	MajorTag   MajorType = 6 // tagged value
	MajorOther MajorType = 7 // float or simple value
)

type Map

type Map []MapEntry

Map is the ordered representation of a CBOR map produced when decoding into an any. It preserves wire order and supports keys of any type (including byte strings, arrays and maps, which a Go map cannot hold). Marshal(Map) re-encodes it as a CBOR map, reporting an error if two entries encode to the same key bytes; Unmarshal accepts a *Map as a decode target. Decode into a Go map[K]V instead when you know the schema and want O(1) lookup.

Example
package main

import (
	"fmt"

	cbor "github.com/MichaelFraser99/go-cbor"
)

func main() {
	var v any
	_ = cbor.Unmarshal([]byte{0xa2, 0x01, 0x02, 0x03, 0x04}, &v) // {1:2, 3:4}
	m := v.(cbor.Map)
	val, _ := m.Get(int64(3))
	fmt.Println(val)
}
Output:
4

func (Map) Get

func (m Map) Get(key any) (any, bool)

Get returns the value for the first entry whose key deep-equals key. Keys must match by exact Go type: integer keys decode as int64, so use Get(int64(k)), not Get(k) with an untyped constant that defaults to int.

func (Map) GetBool

func (m Map) GetBool(key any) (bool, bool)

GetBool returns the value for key as a bool. ok is false if the key is absent or the value is not a bool.

func (Map) GetBytes

func (m Map) GetBytes(key any) ([]byte, bool)

GetBytes returns the value for key as a byte string. ok is false if the key is absent or the value is not a byte string.

func (Map) GetFloat

func (m Map) GetFloat(key any) (float64, bool)

GetFloat returns the value for key as a float64. ok is false if the key is absent or the value is not a float.

func (Map) GetInt

func (m Map) GetInt(key any) (int64, bool)

GetInt returns the value for key as an int64, coercing across the integer representations: it succeeds for a value that decoded as int64, as a uint64 within the int64 range, or as a *big.Int that fits in an int64. ok is false if the key is absent, the value is not an integer, or it does not fit in an int64.

func (Map) GetMap

func (m Map) GetMap(key any) (Map, bool)

GetMap returns the value for key as a nested Map. ok is false if the key is absent or the value is not a map.

func (Map) GetSlice

func (m Map) GetSlice(key any) ([]any, bool)

GetSlice returns the value for key as a []any. ok is false if the key is absent or the value is not an array.

func (Map) GetString

func (m Map) GetString(key any) (string, bool)

GetString returns the value for key as a string. ok is false if the key is absent or the value is not a text string.

func (Map) GetTag

func (m Map) GetTag(key any) (Tag, bool)

GetTag returns the value for key as a Tag. ok is false if the key is absent or the value is not a tag. Note that bignum tags 2 and 3 decode to *big.Int, not Tag.

func (Map) GetUint

func (m Map) GetUint(key any) (uint64, bool)

GetUint returns the value for key as a uint64, coercing across the integer representations: it succeeds for a value that decoded as uint64, as a non-negative int64, or as a *big.Int that fits in a uint64. ok is false if the key is absent, the value is not an integer, or it is negative or too large.

func (Map) ToStringMap

func (m Map) ToStringMap() (map[string]any, error)

ToStringMap converts the Map to a map[string]any, returning an error if any key is not a text string. Nested maps remain as Map values (call ToStringMap on them as needed). Use this at a call site when you know the keys are strings and want a plain Go map; note it discards key order and rejects the non-string keys a Map can otherwise hold.

type MapEntry

type MapEntry struct {
	Key   any
	Value any
}

MapEntry is one key/value pair of a Map.

type Marshaler

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

Marshaler is implemented by types that encode themselves to CBOR. Define MarshalCBOR on a value receiver if instances are ever marshaled by value (including as a field, slice element, or map value): a pointer-receiver method is not in the method set of a non-addressable value, so it is silently skipped and the value is encoded with the default rules instead. MarshalCBOR's bytes are written verbatim and are not validated or re-canonicalised, so returning malformed or non-canonical CBOR breaks the well-formedness or determinism of the surrounding document.

type NaNMode

type NaNMode uint8

NaNMode controls how NaN floats are encoded.

const (
	// NaN7e00 encodes every NaN as the canonical half-precision 0xf97e00.
	NaN7e00 NaNMode = iota
	// NaNNone encodes NaN at the width chosen by FloatMode without canonicalising.
	NaNNone
)

type RawMessage

type RawMessage []byte

RawMessage is a raw encoded CBOR item. It implements Marshaler and Unmarshaler, so a struct field of this type is captured verbatim on decode and re-emitted unchanged on encode — useful for deferred/two-stage decoding and for preserving exact bytes (e.g. a COSE protected header). An empty RawMessage marshals to null.

Example
package main

import (
	"fmt"

	cbor "github.com/MichaelFraser99/go-cbor"
)

func main() {
	type Envelope struct {
		Type int             `cbor:"t"`
		Body cbor.RawMessage `cbor:"b"` // captured verbatim, decoded later
	}
	data, _ := cbor.Marshal(map[string]any{"t": 1, "b": []int{1, 2, 3}})

	var env Envelope
	_ = cbor.Unmarshal(data, &env)
	fmt.Printf("%x\n", []byte(env.Body))

	var body []int
	_ = cbor.Unmarshal(env.Body, &body)
	fmt.Println(body)
}
Output:
83010203
[1 2 3]

func (RawMessage) MarshalCBOR

func (m RawMessage) MarshalCBOR() ([]byte, error)

MarshalCBOR returns m as the raw CBOR encoding, or null for an empty message.

func (*RawMessage) UnmarshalCBOR

func (m *RawMessage) UnmarshalCBOR(data []byte) error

UnmarshalCBOR stores a copy of the raw CBOR bytes in m.

type RawTag

type RawTag struct {
	Number  uint64
	Content RawMessage
}

RawTag is a tag number together with its content as an undecoded RawMessage. It lets a verifier capture a tag's content byte-for-byte without a schema (e.g. a COSE protected header), avoiding the re-canonicalisation that decoding into Tag would apply. Marshal(RawTag{N, raw}) emits tag N wrapping raw's bytes.

Example
package main

import (
	"fmt"

	cbor "github.com/MichaelFraser99/go-cbor"
)

func main() {
	// A verifier captures a tag's content byte-for-byte, without a schema and
	// without the re-canonicalisation that decoding into cbor.Tag would apply.
	msg, _ := cbor.Marshal(cbor.Tag{Number: 18, Content: []int{1, 2}})

	var rt cbor.RawTag
	_ = cbor.Unmarshal(msg, &rt)
	fmt.Printf("tag %d, content %x\n", rt.Number, []byte(rt.Content))
}
Output:
tag 18, content 820102

type SimpleValue

type SimpleValue byte

SimpleValue is a CBOR simple value (major type 7, values 0–19 and 32–255). The named simples true, false and null map to Go bool and nil instead.

func (SimpleValue) String

func (s SimpleValue) String() string

String renders the simple value as simple(N).

type SortMode

type SortMode uint8

SortMode controls how map (and struct-as-map) keys are ordered when encoding.

const (
	// SortBytewise orders keys by the bytewise lexicographic order of their
	// encodings (RFC 8949 §4.2.1 core deterministic). This is the default.
	SortBytewise SortMode = iota
	// SortLengthFirst orders keys by encoded length, then bytewise (RFC 7049 /
	// CTAP2 canonical).
	SortLengthFirst
	// SortNone preserves insertion/declaration order and is non-deterministic
	// for Go maps.
	SortNone
)

type SyntaxError

type SyntaxError struct {
	Offset int64
	// contains filtered or unexported fields
}

SyntaxError reports malformed or not-well-formed CBOR input. Offset is the byte position at which the problem was detected.

func (*SyntaxError) Error

func (e *SyntaxError) Error() string

type Tag

type Tag struct {
	Number  uint64
	Content any
}

Tag is a CBOR tag number together with its content. Marshal(Tag{N, c}) emits tag N wrapping the encoding of c; decoding a tag into an any yields a Tag, except tags 2 and 3 (bignums), which decode to a *big.Int.

type TimeMode

type TimeMode uint8

TimeMode controls how time.Time values are encoded.

const (
	// TimeUnix encodes as tag 1: an integer epoch, or a float when sub-second.
	TimeUnix TimeMode = iota
	// TimeRFC3339 encodes as tag 0: an RFC 3339 text string.
	TimeRFC3339
	// TimeNumericDate encodes as a bare (untagged) numeric epoch — an integer, or a
	// float when sub-second. This is the NumericDate form used by CWT (RFC 8392) and
	// JWT (RFC 7519), where exp/nbf/iat are untagged numbers. The decoder accepts a
	// bare number into a time.Time field regardless of this setting.
	TimeNumericDate
)

type Undefined

type Undefined struct{}

Undefined is the decoded form of the CBOR "undefined" simple value (0xf7). Decoding 0xf7 into an any yields Undefined{}, distinct from other simple values so an inspector can tell them apart. Marshal(Undefined{}) emits 0xf7.

type UnmarshalTypeError

type UnmarshalTypeError struct {
	CBORType string
	GoType   reflect.Type
	Offset   int64
}

UnmarshalTypeError reports a CBOR value that cannot be stored in the target Go type. Offset is the byte position of the value (0 if unknown).

func (*UnmarshalTypeError) Error

func (e *UnmarshalTypeError) Error() string

type Unmarshaler

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

Unmarshaler is implemented by types that decode themselves from CBOR. The input is exactly one well-formed CBOR item and is only valid for the duration of the call; an implementation that retains it must copy it first (data may alias the caller's buffer).

type UnsupportedTypeError

type UnsupportedTypeError struct {
	Type reflect.Type
}

UnsupportedTypeError reports a Go type that cannot be encoded to CBOR.

func (*UnsupportedTypeError) Error

func (e *UnsupportedTypeError) Error() string

Jump to

Keyboard shortcuts

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