cbor

package
v1.2.5 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

README

encoding/cbor

A bounded, reflection-free RFC 8949 codec for TinyGo and Go. It preserves signed integer labels, rejects hostile input, and never maps arbitrary structs, which suits WebAuthn authenticator data and COSE keys as well as compact realtime message formats.

Supported subset

  • unsigned and negative integers, including the full encoded negative range on decode
  • byte and UTF-8 text strings
  • arrays and maps
  • booleans, null, tags, and IEEE 754 half/single/double input
  • definite and indefinite-length input
  • deterministic output, with a selectable map key ordering
  • incremental io.Reader decoding with input, nesting, container, string, and retained-raw-message limits
  • optional duplicate map key rejection; that mode validates a bounded root item before exposing its tokens
  • explicit sequence mode; normal mode rejects bytes after one root item

Two decoders, two encoders

Decoder reads incrementally from an io.Reader and copies what it returns. Use it for input that arrives over a connection, or that is larger than memory should hold at once.

Reader reads from a byte slice already in memory. It borrows strings instead of copying them, skips an item without allocating it, and captures a sub-item at any depth — none of which an incremental decoder can do. Reuse one per connection with Reset.

On the writing side, Encoder writes whole items to an io.Writer, and the Append* functions write into a caller-owned []byte. AppendArrayHeader and AppendMapHeader let a nested structure be written in one pass, rather than requiring every child to be a finished RawMessage first.

buf = cbor.AppendArrayHeader(buf[:0], 4)
buf = cbor.AppendUint(buf, tick)
buf = moveX.AppendCBORTo(buf)   // a type carrying its own encoding
buf = cbor.AppendUint(buf, buttons)

Carrying your own encoding

A type says how it encodes by implementing one of:

type Appender  interface { AppendCBORTo(dst []byte) []byte }
type Decodable interface { DecodeCBORFrom(data []byte) error } // pointer receiver

They append into the destination rather than returning bytes, so a nested field costs no allocation of its own. AppendCBORTo returns no error; the obligation that creates is that it appends exactly one valid, complete item. Nothing in the type system can hold a foreign implementation to that, so Profile.ValidateAppended checks what it actually wrote.

Profiles

A Profile is a named restriction, so both ends name the same shape instead of assembling limits by hand.

  • Wire() — fixed-order arrays, no maps, no tags, no floats, no indefinite lengths, small bounds. Field names never appear, which is what makes it small and why a version mismatch has to be settled before any message is read.
  • World() — maps, optional fields and tags, bytewise key order, bounds sized for snapshots rather than ticks.

Both refuse floats: numerics are scaled integers, so a float is a protocol violation rather than a value, and it is refused at encode and at decode.

if err := cbor.Wire().Validate(data); err != nil { /* not a wire message */ }

Profile.Validate answers the question without decoding the item into anything.

Cost

A fixed-shape wire message, encoded and decoded through a reused buffer and a reused Reader:

ns/op allocs/op
encode, Append* 9.2 0
encode, WriteArray over RawMessage children 100.4 5
decode, Reader 42.4 0
decode, Decoder over an io.Reader 168.0 7
Wire().Validate 23.9 0
World().Validate 90.0 0
Skip an unknown field 24.2 0

Measured on darwin/arm64 with go test -bench . -benchtime 3s. The point is the allocation column: the steady state of a tick loop has to be free of it.

Errors

Every refusal wraps one of the package sentinels, so errors.Is works as before, and adds where it happened:

cbor: malformed input: reserved additional information 28 (at byte 5, at [2][1])

errors.As reaches the *cbor.Error for the offset and the route. Nothing tracks a route while decoding succeeds — it is built afterwards by walking the input again — so a message that decodes cleanly pays nothing for this.

Map key ordering

RFC 8949 defines two deterministic orderings and they disagree. EncoderOptions.KeyOrder selects one:

  • LengthFirstKeyOrder (the zero value) sorts shorter encoded keys first, then bytewise. This is §4.2.3, and it is what CTAP2 canonical CBOR and COSE require.
  • BytewiseKeyOrder sorts bytewise over the whole encoded key. This is §4.2.1 Core Deterministic Encoding.

The keys -1 and 100 encode as 20 and 1864, and the two rules order them differently. WriteRaw enforces whichever ordering the encoder was configured with, so a raw item canonical under one is rejected under the other.

Intentionally unsupported

  • reflection-based struct or arbitrary Go value mapping
  • CBOR diagnostic notation
  • unassigned simple values and CBOR undefined
  • indefinite-length encoding (it cannot be deterministic)
  • COSE signing, encryption, or key management

For untrusted maps, enable DecoderOptions.RejectDuplicateMapKeys. This mode may retain one root item up to MaxRawMessageBytes so duplicate keys can be checked before application code observes any field.

Documentation

Overview

Package cbor implements a bounded, reflection-free subset of RFC 8949.

Decoder exposes typed tokens instead of mapping CBOR to arbitrary Go values. Encoder writes deterministic output and provides helpers for deterministically ordered arrays and maps. Nothing in either path uses reflection, io.ReadAll, or struct tags.

Map key ordering

RFC 8949 defines two deterministic map key orderings, and they produce different bytes for the same map. EncoderOptions.KeyOrder selects between them. The zero value is LengthFirstKeyOrder, the section 4.2.3 length-first ordering that CTAP2 canonical CBOR and COSE require; BytewiseKeyOrder is the section 4.2.1 Core Deterministic Encoding ordering. Callers that care which one reaches the wire should set the field rather than inherit it.

Bounds

Every limit is explicit and every limit is enforced before anything is reserved: a declared length never becomes an allocation on its own, because the length prefix of a string arrives before its bytes and is attacker controlled. DecoderOptions.RejectDuplicateMapKeys additionally validates a bounded root item before exposing any of its tokens, at the cost of retaining up to MaxRawMessageBytes.

Intended uses

Security-sensitive formats where preserving signed integer labels and rejecting hostile input matter more than mapping arbitrary structs: WebAuthn authenticator data and COSE_Key on one side, compact realtime game messages on the other.

The package intentionally does not support struct tags, diagnostic notation, COSE signing, encryption, key management, or indefinite-length output.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrMalformed       = errors.New("cbor: malformed input")
	ErrTruncated       = errors.New("cbor: truncated input")
	ErrLimitExceeded   = errors.New("cbor: limit exceeded")
	ErrDuplicateMapKey = errors.New("cbor: duplicate map key")
	ErrExtraneousData  = errors.New("cbor: extraneous data after root item")
	ErrUnexpectedToken = errors.New("cbor: unexpected token")
	ErrIntegerOverflow = errors.New("cbor: integer does not fit int64")
	// ErrProfileViolation reports CBOR that is well formed but not legal under
	// the profile it was read or written under.
	ErrProfileViolation = errors.New("cbor: profile violation")
	// ErrFloatRefused reports a float where the configuration carries scaled
	// integers instead. It is a ErrProfileViolation with its own identity,
	// because a float leak is the specific failure a deterministic simulation
	// most needs to be told about.
	ErrFloatRefused = fmt.Errorf("%w: float", ErrProfileViolation)
)

Functions

func AppendArrayHeader

func AppendArrayHeader(dst []byte, n int) []byte

AppendArrayHeader appends a definite-length array head for n items, which the caller then appends in order.

This is the half of the encoder that was missing. WriteArray takes children that are already finished byte slices, so a parent cannot be written until every descendant has been built and copied; the cost of that scales with the depth of the tree. Appending a header instead lets a nested structure be written in one pass into one buffer.

func AppendBool

func AppendBool(dst []byte, v bool) []byte

AppendBool appends a boolean.

func AppendBytes

func AppendBytes(dst, v []byte) []byte

AppendBytes appends a byte string.

func AppendFloat

func AppendFloat(dst []byte, v float64) []byte

AppendFloat appends a float in the shortest form that round-trips, which is what makes float output deterministic. A wire Profile refuses floats outright; this exists for the world profile and for COSE.

func AppendInt

func AppendInt(dst []byte, v int64) []byte

AppendInt appends an integer of either sign in its shortest form.

func AppendMapHeader

func AppendMapHeader(dst []byte, n int) []byte

AppendMapHeader appends a definite-length map head for n key/value pairs.

Nothing sorts the pairs the caller then appends. A streaming writer cannot: sorting needs every key at once, which is the shape this exists to avoid. Generated code knows its field set before it runs and can emit the pairs in order; hand-written callers that need the sort should keep using Encoder.WriteMap, and either way Validate under a Profile is what proves the result.

func AppendNegative

func AppendNegative(dst []byte, arg uint64) []byte

AppendNegative appends the negative integer -1-arg. It reaches the whole encoded negative range, including the half below the int64 floor that AppendInt cannot express; the decoder has always been able to read that far.

func AppendNull

func AppendNull(dst []byte) []byte

AppendNull appends the null value.

func AppendRaw

func AppendRaw(dst []byte, raw RawMessage) []byte

AppendRaw appends an item that is already encoded, without validating it.

func AppendTag

func AppendTag(dst []byte, tag uint64) []byte

AppendTag appends a tag head. The tagged content is the next item appended.

func AppendText

func AppendText(dst []byte, v string) []byte

AppendText appends a text string. It does not validate UTF-8.

func AppendUint

func AppendUint(dst []byte, v uint64) []byte

AppendUint appends an unsigned integer in its shortest form.

func Validate

func Validate(data []byte, opts DecoderOptions) error

Validate checks that data contains exactly one bounded CBOR item.

Types

type Appender

type Appender interface {
	AppendCBORTo(dst []byte) []byte
}

Appender is implemented by a type that carries its own CBOR encoding.

AppendCBORTo appends exactly one complete CBOR item to dst and returns the extended buffer, the way the strconv.Append and time.AppendFormat families do. It takes a destination rather than returning a fresh slice because a value returning bytes allocates once per value and undoes the caller's buffer pooling at every nested field, which a message per player per tick cannot afford.

It returns no error. The append path below this point carries none, and the obligation that creates is on the implementation: for every value of the type, it must append one valid, complete CBOR item. Nothing here can check that, so an encoder that cares -- one writing under a Profile -- should validate the bytes a foreign implementation appended before they reach the wire. See Profile.ValidateAppended.

type Decodable

type Decodable interface {
	DecodeCBORFrom(data []byte) error
}

Decodable is implemented by a type that carries its own CBOR decoding.

DecodeCBORFrom decodes the single CBOR item in data into the receiver, which must be a pointer. data holds exactly one item and nothing after it; Reader.ReadRaw is what produces it, at whatever depth the field sits.

type Decoder

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

Decoder incrementally reads CBOR from an io.Reader without io.ReadAll. ReadToken exposes container boundaries; typed Read methods are conveniences that reject a token of the wrong kind.

Example
data := []byte{0xa2, 0x01, 0x02, 0x20, 0x42, 0xca, 0xfe}
d, _ := NewDecoder(bytes.NewReader(data), DecoderOptions{RejectDuplicateMapKeys: true})
pairs, _, _ := d.ReadMap()
fmt.Println(pairs)
Output:
2

func NewDecoder

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

func (*Decoder) ReadArray

func (d *Decoder) ReadArray() (length int, indefinite bool, err error)

func (*Decoder) ReadBool

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

func (*Decoder) ReadBytes

func (d *Decoder) ReadBytes() ([]byte, error)

func (*Decoder) ReadFloat

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

func (*Decoder) ReadInt

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

func (*Decoder) ReadMap

func (d *Decoder) ReadMap() (pairs int, indefinite bool, err error)

func (*Decoder) ReadNull

func (d *Decoder) ReadNull() error

func (*Decoder) ReadRaw

func (d *Decoder) ReadRaw() (RawMessage, error)

ReadRaw reads and validates exactly one item while retaining at most MaxRawMessageBytes. In non-sequence mode it also rejects trailing data.

func (*Decoder) ReadTag

func (d *Decoder) ReadTag() (uint64, error)

func (*Decoder) ReadText

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

func (*Decoder) ReadToken

func (d *Decoder) ReadToken() (Token, error)

ReadToken reads the next typed token. Definite container end tokens are synthesized when the declared item count is exhausted. For a non-sequence decoder, the call after the root token returns io.EOF only after confirming that no trailing byte exists.

func (*Decoder) ReadUint

func (d *Decoder) ReadUint() (uint64, error)

type DecoderOptions

type DecoderOptions struct {
	MaxInputBytes          int64
	MaxNestedLevels        int
	MaxContainerItems      int
	MaxStringBytes         int
	MaxRawMessageBytes     int
	RejectDuplicateMapKeys bool
	Sequence               bool
	// RejectFloats refuses every float on input. Under a profile that carries
	// scaled integers, a float on the wire is a protocol violation rather than
	// a value, and catching it here makes it an error on the receiving side
	// instead of a disagreement about what the message meant.
	RejectFloats bool
}

DecoderOptions controls resource limits and stream behavior. A zero limit selects a conservative default. Negative limits are rejected by NewDecoder.

type Encoder

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

Encoder writes deterministic RFC 8949. Each method writes one complete item. WriteArray and WriteMap validate their child RawMessages before writing; WriteMap sorts keys under EncoderOptions.KeyOrder, which defaults to the length-first ordering CTAP2 and COSE require rather than to RFC 8949 Core Deterministic Encoding. Indefinite-length output is not supported, because it cannot be deterministic.

Example
var out bytes.Buffer
e, _ := NewEncoder(&out, EncoderOptions{})
key, _ := MarshalText("alg")
_ = e.WriteMap([]MapEntry{{Key: key, Value: MarshalInt(-7)}})
fmt.Println(len(out.Bytes()))
Output:
6

func NewEncoder

func NewEncoder(w io.Writer, opts EncoderOptions) (*Encoder, error)
Example
package main

import (
	"bytes"
	"fmt"

	"github.com/shibukawa/tinygodriver/encoding/cbor"
)

func main() {
	var encoded bytes.Buffer
	encoder, err := cbor.NewEncoder(&encoded, cbor.EncoderOptions{})
	if err != nil {
		panic(err)
	}
	if err := encoder.WriteText("ok"); err != nil {
		panic(err)
	}
	fmt.Printf("%x\n", encoded.Bytes())
}
Output:
626f6b

func (*Encoder) Reset

func (e *Encoder) Reset(w io.Writer) error

Reset points the Encoder at a new writer, keeping its options, so a session can hold one encoder instead of allocating one per message.

func (*Encoder) WriteArray

func (e *Encoder) WriteArray(items []RawMessage) error

func (*Encoder) WriteBool

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

func (*Encoder) WriteBytes

func (e *Encoder) WriteBytes(v []byte) error

func (*Encoder) WriteFloat

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

func (*Encoder) WriteInt

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

func (*Encoder) WriteMap

func (e *Encoder) WriteMap(entries []MapEntry) error

func (*Encoder) WriteNegative

func (e *Encoder) WriteNegative(arg uint64) error

WriteNegative writes the negative integer -1-arg. See AppendNegative.

func (*Encoder) WriteNull

func (e *Encoder) WriteNull() error

func (*Encoder) WriteRaw

func (e *Encoder) WriteRaw(raw RawMessage) error

WriteRaw writes one already deterministic item after validating it.

func (*Encoder) WriteTag

func (e *Encoder) WriteTag(tag uint64, content RawMessage) error

func (*Encoder) WriteText

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

func (*Encoder) WriteUint

func (e *Encoder) WriteUint(v uint64) error

type EncoderOptions

type EncoderOptions struct {
	MaxNestedLevels   int
	MaxContainerItems int
	MaxStringBytes    int
	// KeyOrder selects the map key ordering WriteMap emits and WriteRaw
	// enforces. The zero value keeps the CTAP2 and COSE ordering.
	KeyOrder KeyOrder
}

EncoderOptions controls deterministic output limits and the map key ordering. Zero selects a conservative default. Indefinite-length output is deliberately unsupported.

type Error

type Error struct {
	// Offset is the byte position in the input at which the failing item began.
	Offset int64
	// Path names the container route to the failing item where one is known,
	// as it would be written in diagnostic notation, and is empty otherwise.
	Path string
	Err  error
}

Error locates a decode failure. It wraps one of the package sentinels, so errors.Is keeps working unchanged, and adds the offset at which the failing item began.

A byte-format error is otherwise only as useful as the caller's ability to find it. Rejecting one attestation needs the sentinel; comparing two builds that disagree about a message needs the position.

func (*Error) Error

func (e *Error) Error() string

func (*Error) Unwrap

func (e *Error) Unwrap() error

type KeyOrder

type KeyOrder uint8

KeyOrder selects which deterministic map key ordering an Encoder emits and enforces. RFC 8949 defines two, and they produce different bytes for the same map, so the choice is part of the wire contract rather than an internal detail. The zero value is LengthFirstKeyOrder.

const (
	// LengthFirstKeyOrder sorts shorter encoded keys first and breaks ties
	// bytewise. This is the length-first ordering of RFC 8949 section 4.2.3,
	// which is what CTAP2 canonical CBOR and COSE require.
	LengthFirstKeyOrder KeyOrder = iota
	// BytewiseKeyOrder sorts bytewise lexicographically over the whole encoded
	// key with no length pass. This is RFC 8949 section 4.2.1 Core
	// Deterministic Encoding.
	BytewiseKeyOrder
)

func (KeyOrder) String

func (o KeyOrder) String() string

type MapEntry

type MapEntry struct {
	Key   RawMessage
	Value RawMessage
}

MapEntry is one encoded key/value pair for Encoder.WriteMap. Key and Value must each contain exactly one CBOR item. Keys are sorted according to Core Deterministic Encoding before they are written.

type Profile

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

A Profile is a named restriction on what CBOR is legal, so a caller names the shape it wants rather than assembling limits by hand and hoping both ends assembled the same ones.

A Profile only enforces. It never infers which profile a message should be read under; that belongs to the schema and to the caller.

func Wire

func Wire() Profile

Wire returns the compact profile for realtime messages.

A struct encodes as a fixed-order array with no field names, which is what makes it small and what makes a version mismatch undetectable from the bytes alone: there is nothing in the message to disagree about a field with. That is why the protocol version has to be agreed before any message is read, rather than negotiated per field.

Numerics are scaled integers. Floats are refused outright, at encode and at decode, so a float that reaches the wire is a caught protocol violation rather than two peers drifting apart.

func World

func World() Profile

World returns the evolvable profile for snapshots and episode logs.

It admits maps, optional fields and tags, so a schema can grow, and it holds map keys in bytewise order -- RFC 8949 section 4.2.1 Core Deterministic Encoding -- rather than the length-first order CTAP2 requires, because nothing here is COSE.

Its bounds are larger than the wire profile's because a snapshot is larger than a tick. In particular MaxRawMessageBytes is set deliberately: duplicate key detection retains a whole root item, and the 1 MiB default would refuse snapshots this profile is meant to carry.

func (Profile) AllowingFloats

func (p Profile) AllowingFloats() Profile

AllowingFloats returns a copy of p that admits floats. A profile carrying scaled integers should not need it; it exists so that a caller who has decided otherwise says so at the call site rather than by editing a preset.

func (Profile) DecoderOptions

func (p Profile) DecoderOptions() DecoderOptions

DecoderOptions returns the limits this profile implies, for NewDecoder or NewReader.

func (Profile) EncoderOptions

func (p Profile) EncoderOptions() EncoderOptions

EncoderOptions returns the limits and key ordering this profile implies.

func (Profile) Name

func (p Profile) Name() string

Name reports the profile's name, which appears in its refusals.

func (Profile) NewReader

func (p Profile) NewReader(data []byte) (*Reader, error)

NewReader returns a Reader over data with this profile's limits.

func (Profile) ReaderOver

func (p Profile) ReaderOver(data []byte) Reader

ReaderOver returns a Reader by value with this profile's limits. See ReaderOver.

func (Profile) Validate

func (p Profile) Validate(data []byte) error

Validate reports whether data is exactly one item legal under p. It answers the question without decoding the item into anything, which is what makes it usable as a boundary check on bytes from somewhere else.

func (Profile) ValidateAppended

func (p Profile) ValidateAppended(dst []byte, before int) error

ValidateAppended checks the item a foreign AppendCBORTo just wrote, given the buffer and the length it had before the call.

A type that carries its own encoding cannot be made to honour a profile by the type system: nothing stops it appending a float, an indefinite-length item, or an unsorted map into a message that must not contain one. Nothing downstream would notice either, because the bytes are well-formed CBOR -- they are simply not the CBOR this profile promised. Running this after the call is what turns that from a silent divergence into an error.

func (Profile) WithMaxInputBytes

func (p Profile) WithMaxInputBytes(n int64) Profile

WithMaxInputBytes returns a copy of p with a different input bound.

type RawMessage

type RawMessage []byte

RawMessage holds exactly one validated CBOR item when returned by Decoder. Callers constructing RawMessage directly should pass it through Validate or Encoder.WriteRaw before trusting it.

func MarshalBool

func MarshalBool(v bool) RawMessage

func MarshalBytes

func MarshalBytes(v []byte) RawMessage

func MarshalFloat

func MarshalFloat(v float64) RawMessage

func MarshalInt

func MarshalInt(v int64) RawMessage

func MarshalNegative

func MarshalNegative(arg uint64) RawMessage

MarshalNegative returns the negative integer -1-arg as a RawMessage, reaching the range MarshalInt cannot. See AppendNegative.

func MarshalNull

func MarshalNull() RawMessage

func MarshalText

func MarshalText(v string) (RawMessage, error)

func MarshalUint

func MarshalUint(v uint64) RawMessage

Raw constructors make deterministic primitive values convenient to use in WriteArray and WriteMap.

type Reader

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

Reader decodes CBOR from a byte slice already in memory. It is the counterpart of Decoder for callers that have the whole item: it borrows strings from the input instead of copying them, skips an item without allocating it, and captures a sub-item at any depth, none of which an incremental io.Reader decoder can do.

Every slice a Reader returns aliases the input. They stay valid for as long as the caller keeps the input alive and does not modify it; Reset severs nothing, so a slice from a previous input outlives the Reader but not the bytes behind it. Callers that need independent storage should copy.

A Reader is not safe for concurrent use. Reuse one per connection rather than allocating one per message; that is what Reset is for.

func NewReader

func NewReader(data []byte, opts DecoderOptions) (*Reader, error)

NewReader returns a Reader over data. A zero limit in opts selects the same conservative default NewDecoder uses.

func ReaderOver

func ReaderOver(data []byte, opts DecoderOptions) Reader

ReaderOver returns a Reader by value, for a caller that wants it on the stack.

NewReader returns a pointer, which escapes, and a DecodeCBORFrom implementation runs once per field per message: at that rate the constructor is the allocation. A negative limit is treated as unset here rather than refused, because there is no error to return.

func (*Reader) Done

func (r *Reader) Done() bool

Done reports whether the whole input has been consumed.

func (*Reader) Offset

func (r *Reader) Offset() int

Offset reports how many bytes have been consumed, which is where the next item begins.

func (*Reader) Peek

func (r *Reader) Peek() (TokenKind, error)

Peek reports the kind of the next item without consuming it. It is the way to branch on an optional field: a caller that would otherwise have to capture and rewind can dispatch instead.

func (*Reader) ReadArrayHeader

func (r *Reader) ReadArrayHeader() (length int, indefinite bool, err error)

ReadArrayHeader reads an array head and returns its length. A definite-length array reports indefinite false and its item count; an indefinite one reports true and a length of -1, and ends at the item Peek reports as EndArray.

func (*Reader) ReadBool

func (r *Reader) ReadBool() (bool, error)

ReadBool reads a boolean.

func (*Reader) ReadBreak

func (r *Reader) ReadBreak() error

ReadBreak consumes the break that ends an indefinite-length container.

func (*Reader) ReadBytes

func (r *Reader) ReadBytes() ([]byte, error)

ReadBytes returns a byte string borrowed from the input.

func (*Reader) ReadFloat

func (r *Reader) ReadFloat() (float64, error)

ReadFloat reads a half, single, or double precision float.

func (*Reader) ReadInt

func (r *Reader) ReadInt() (int64, error)

ReadInt reads an integer of either sign. A negative integer outside the int64 range is ErrIntegerOverflow; ReadRaw preserves it where the value itself is needed.

func (*Reader) ReadInt8

func (r *Reader) ReadInt8() (int8, error)

Sized integer reads. The encoder writes the shortest form, so a field declared int32 arrives as anything from one to five bytes and its width is carried by the schema rather than the bytes. These enforce the declared width, so a value outside it is a protocol error rather than a silent wrap.

func (*Reader) ReadInt16

func (r *Reader) ReadInt16() (int16, error)

func (*Reader) ReadInt32

func (r *Reader) ReadInt32() (int32, error)

func (*Reader) ReadInt64

func (r *Reader) ReadInt64() (int64, error)

ReadInt64 is ReadInt under the name the sized set uses.

func (*Reader) ReadMapHeader

func (r *Reader) ReadMapHeader() (pairs int, indefinite bool, err error)

ReadMapHeader reads a map head and returns its pair count, on the same terms as ReadArrayHeader.

func (*Reader) ReadNull

func (r *Reader) ReadNull() error

ReadNull reads the null value.

func (*Reader) ReadRaw

func (r *Reader) ReadRaw() (RawMessage, error)

ReadRaw returns the bytes of exactly one item, at whatever depth the Reader currently sits, and advances past it. The result aliases the input.

This is the primitive a type that carries its own decoding needs: a field of a foreign type is always nested inside something, and handing that type its own bytes is the only way to decode it without knowing its shape.

func (*Reader) ReadTag

func (r *Reader) ReadTag() (uint64, error)

ReadTag reads a tag head and leaves its content as the next item.

func (*Reader) ReadText

func (r *Reader) ReadText() (string, error)

ReadText returns a text string as a Go string, which copies it.

func (*Reader) ReadTextBytes

func (r *Reader) ReadTextBytes() ([]byte, error)

ReadTextBytes returns a text string borrowed from the input, without the allocation ReadText's string conversion costs.

func (*Reader) ReadUint

func (r *Reader) ReadUint() (uint64, error)

ReadUint reads an unsigned integer.

func (*Reader) ReadUint8

func (r *Reader) ReadUint8() (uint8, error)

func (*Reader) ReadUint16

func (r *Reader) ReadUint16() (uint16, error)

func (*Reader) ReadUint32

func (r *Reader) ReadUint32() (uint32, error)

func (*Reader) ReadUint64

func (r *Reader) ReadUint64() (uint64, error)

ReadUint64 is ReadUint under the name the sized set uses.

func (*Reader) Remaining

func (r *Reader) Remaining() int

Remaining reports how many bytes are left unconsumed.

func (*Reader) Reset

func (r *Reader) Reset(data []byte)

Reset points the Reader at a new input, keeping its options. Slices returned before the call still alias the old input.

func (*Reader) Skip

func (r *Reader) Skip() error

Skip advances past exactly one complete item, at any depth, without allocating and without materializing what it passed. It is how a decoder tolerates a field it does not know: the alternative, capturing the item only to discard it, is what makes an evolving schema expensive.

type Token

type Token struct {
	Kind       TokenKind
	Argument   uint64
	Bytes      []byte
	Text       string
	Bool       bool
	Float      float64
	Length     int
	Indefinite bool
}

Token is a typed CBOR token. Argument stores the unsigned argument for integers and tags. A NegativeInteger represents -1-Argument, retaining the full RFC 8949 range even when it cannot fit in int64.

func (Token) Int64

func (t Token) Int64() (int64, error)

type TokenKind

type TokenKind uint8
const (
	InvalidToken TokenKind = iota
	UnsignedInteger
	NegativeInteger
	ByteString
	TextString
	StartArray
	EndArray
	StartMap
	EndMap
	Boolean
	Null
	Tag
	Float
)

func (TokenKind) String

func (k TokenKind) String() string

Jump to

Keyboard shortcuts

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