encoding.cbor #
Description
encoding.cbor is an RFC 8949 Concise Binary Object Representation codec.
CBOR is a compact, schema-free binary format that supports the same value model as JSON (numbers, strings, arrays, maps) plus byte strings, tagged items, IEEE 754 floats at three widths, and a small set of "simple" values (true, false, null, undefined). It is used by COSE/CWT (IETF security stack), WebAuthn/FIDO2, the Matter smart-home protocol, and many IoT stacks because messages are typically 30–60 % smaller than JSON and parse without quoting/escaping.
Three layers of API are available:
encode[T]/decode[T]— comptime-driven generic API. Works on primitives, strings, arrays, maps, structs (with@[cbor: 'name'],@[skip],@[cbor_rename_all: 'snake_case']), enums,time.Time(auto-tagged), and any type implementingMarshaler/Unmarshaler.Packer/Unpacker— manual streaming API. Use when the schema isn't known at compile time, or when you need full control over tags, indefinite-length items and simple values.Valuesumtype — dynamic representation for round-tripping unknown payloads or inspecting tagged data.
Defaults follow RFC 8949 preferred serialisation (§4.2.2): floats shrink to the shortest IEEE 754 width that preserves their value, and every length argument uses the shortest encoding. Set EncodeOpts.canonical = true to additionally sort map keys for hash/signature stability (§4.2.1, deterministic encoding). Set EncodeOpts.validate_utf8 = true if callers may build strings from raw bytes (e.g. bytestr()) — the streaming pack_text trusts its input for performance, but encode[T] will then refuse to emit non-UTF-8 text strings the strict-by-default decoder would reject on the way back.
Usage
encode[T] / decode[T]
import encoding.cbor
import time
struct Person {
name string
age int
email ?string
birthday time.Time
}
fn main() {
bob := Person{
name: 'Bob'
age: 30
birthday: time.now()
}
bytes := cbor.encode[Person](bob, cbor.EncodeOpts{})!
// bytes is []u8 — wire-ready CBOR
back := cbor.decode[Person](bytes, cbor.DecodeOpts{})!
assert back.name == 'Bob'
}
Optional fields (?T) encode as CBOR null when set to none. Enums encode as their underlying integer.
Struct attributes
@[cbor_rename_all: 'kebab-case']
struct Login {
user_name string @[cbor: 'u'] // emit/read key "u" (overrides rename_all)
password string @[skip] // never serialise
remember bool // becomes "remember"
is_admin bool // becomes "is-admin"
}
The @[cbor_rename_all: '...'] attribute on a struct applies a global rename strategy to every field that doesn't have an explicit @[cbor: '...'] override — supported strategies: snake_case, camelCase, PascalCase, kebab-case, SCREAMING_SNAKE_CASE. Use @[cbor: '-'] as an alternative to @[skip].
Manual streaming with Packer / Unpacker
Use this when the schema is dynamic or when you need access to CBOR features that don't map directly to V types (tags, indefinite-length strings, custom simple values):
import encoding.cbor
fn main() {
mut p := cbor.new_packer(cbor.EncodeOpts{})
p.pack_array_header(3)
p.pack_uint(42)
p.pack_text('hello')
p.pack_bool(true)
bytes := p.bytes()
mut u := cbor.new_unpacker(bytes, cbor.DecodeOpts{})
n := u.unpack_array_header()! // 3
a := u.unpack_uint()! // 42
b := u.unpack_text()! // 'hello'
c := u.unpack_bool()! // true
_ = n
_ = a
_ = b
_ = c
}
Dynamic values with Value
When the payload schema is unknown at compile time, decode into cbor.Value and walk the sumtype:
import encoding.cbor
fn main() {
bytes := cbor.encode[map[string]int]({
'a': 1
'b': 2
}, cbor.EncodeOpts{})!
v := cbor.decode[cbor.Value](bytes, cbor.DecodeOpts{})!
if val := v.get('a') {
if i := val.as_int() {
assert i == 1
}
}
}
Value covers every CBOR type: IntNum, FloatNum, Text, Bytes, Array, Map, Tag, Bool, Null, Undefined, Simple. Re-encoding a Value round-trips bit-for-bit when the source was already in preferred form.
Custom Marshaler / Unmarshaler
For types that need a custom on-wire representation, implement either side of the interface:
import encoding.cbor
struct Color {
mut:
r u8
g u8
b u8
}
pub fn (c Color) to_cbor() []u8 {
mut p := cbor.new_packer(cbor.EncodeOpts{})
p.pack_array_header(3)
p.pack_uint(c.r)
p.pack_uint(c.g)
p.pack_uint(c.b)
return p.bytes().clone()
}
pub fn (mut c Color) from_cbor(data []u8) ! {
mut u := cbor.new_unpacker(data, cbor.DecodeOpts{})
n := u.unpack_array_header()!
if n != 3 {
return error('Color expects 3 elements')
}
c.r = u8(u.unpack_uint()!)
c.g = u8(u.unpack_uint()!)
c.b = u8(u.unpack_uint()!)
}
to_cbor must return exactly one well-formed CBOR data item — the generic encoder copies the bytes verbatim. from_cbor receives a slice already trimmed to one item.
Canonical (deterministic) encoding
For hashing or signing, set canonical: true so that map keys are sorted by length-then-lexicographic order (RFC 8949 §4.2.1):
import encoding.cbor
bytes := cbor.encode[map[string]int]({
'b': 2
'a': 1
}, cbor.EncodeOpts{ canonical: true })!
// keys are emitted in the order "a", "b" regardless of input order
Tags and time.Time
Values of type time.Time round-trip losslessly: whole-second values use tag 1 (epoch seconds, integer) for the smallest canonical wire, and sub-second values use tag 0 (RFC 3339 string with nanosecond precision) — necessary because a tag-1 float can't carry both a 10-digit unix epoch and 9 fractional digits. Decode accepts tag 0 (RFC 3339 text, any sub-second precision) or tag 1 (integer or float). Custom tags can be emitted/read via pack_tag / unpack_tag or by constructing a Value with cbor.new_tag(number, content).
Conformance
The test suite (vlib/encoding/cbor/tests/) covers every vector from RFC 8949 Appendix A, plus indefinite-length strings, depth limits, malformed-input rejection, UTF-8 validation, canonical ordering, and tagged time round-trips.
v test vlib/encoding/cbor/tests/
Constants #
const tag_date_time = u64(0) // RFC 3339 date/time text string
const tag_epoch = u64(1) // POSIX epoch seconds (int or float)
const tag_unsigned_bignum = u64(2) // byte string, big-endian magnitude
const tag_negative_bignum = u64(3) // byte string, -(1 + n)
const tag_decimal_fraction = u64(4) // [exponent, mantissa] with base 10
const tag_bigfloat = u64(5) // [exponent, mantissa] with base 2
const tag_base64url_hint = u64(21)
const tag_base64_hint = u64(22)
const tag_base16_hint = u64(23)
const tag_embedded_cbor = u64(24) // byte string holding well-formed CBOR
const tag_uri = u64(32) // RFC 3986 URI as text string
const tag_base64url = u64(33)
const tag_base64 = u64(34)
const tag_self_describe = u64(55799) // CBOR magic prefix
const self_describe_prefix = [u8(0xd9), 0xd9, 0xf7]
Magic prefix d9d9f7 produced when wrapping any value in tag 55799.
fn decode #
fn decode[T](data []u8, opts DecodeOpts) !T
decode parses CBOR bytes into a value of type T. Rejects extra bytes after the top-level item by default — callers feeding a buffer that holds multiple concatenated items (or that may carry an unrelated suffix) must opt in via DecodeOpts.allow_trailing_bytes = true and drive an Unpacker themselves.
A leading self-describe tag (d9 d9 f7, RFC 8949 §3.4.6) is stripped transparently so payloads encoded with EncodeOpts.self_describe round-trip through decode[T] without the caller having to peel it.
fn decode_from #
fn decode_from[T](mut r io.Reader, opts DecodeOpts) !T
decode_from reads bytes from r until EOF (or until DecodeOpts.max_stream_bytes is hit) and decodes a single top-level value. For multi-value streams, use Unpacker directly on a pre-buffered slice.
Always set max_stream_bytes on untrusted readers — otherwise a peer that never sends EOF blocks the call forever.
fn encode #
fn encode[T](val T, opts EncodeOpts) ![]u8
encode serialises any V value into CBOR bytes. The returned slice owns its backing buffer (V's GC tracks it) — no copy, so the returned bytes are safe to keep across calls and to pass to other modules.
fn encode_to #
fn encode_to[T](val T, mut w io.Writer, opts EncodeOpts) !
encode_to serialises val into an internal buffer, then writes the bytes to w in a loop until everything is accepted. Errors on the first I/O failure.
fn encode_value #
fn encode_value(v Value, opts EncodeOpts) ![]u8
encode_value emits a Value tree to a fresh byte slice with default opts.
fn new_bytes #
fn new_bytes(b []u8) Value
new_bytes wraps a []u8 as a CBOR byte-string Value.
fn new_float #
fn new_float(v f64) Value
new_float wraps an f64 as a CBOR FloatNum that re-encodes at full precision unless f64_to_half / f32 conversion is lossless.
fn new_int #
fn new_int(n i64) Value
new_int wraps a signed i64 in a Value, picking unsigned vs negative.
fn new_negative #
fn new_negative(magnitude u64) Value
new_negative wraps the encoded argument of a major-type-1 value, where the actual integer is -1 - magnitude. Useful when magnitude exceeds i64.
fn new_packer #
fn new_packer(opts EncodeOpts) Packer
new_packer builds a Packer with the given options. opts.initial_cap reserves the buffer up-front; oversize is harmless, undersize triggers the usual growth policy.
fn new_tag #
fn new_tag(number u64, content Value) Value
new_tag wraps an existing Value with a tag number.
fn new_text #
fn new_text(s string) Value
new_text wraps a string as a CBOR text Value.
fn new_uint #
fn new_uint(n u64) Value
new_uint wraps a u64 in a Value (unsigned-int variant).
fn new_unpacker #
fn new_unpacker(data []u8, opts DecodeOpts) Unpacker
new_unpacker constructs an Unpacker over the given byte slice.
fn FloatBits.from #
fn FloatBits.from[W](input W) !FloatBits
fn Kind.from #
fn Kind.from[W](input W) !Kind
interface Marshaler #
interface Marshaler {
to_cbor() []u8
}
Marshaler lets a user type control its own CBOR encoding. Returned bytes must be exactly one well-formed CBOR data item — the generic encoder copies them verbatim, so malformed output corrupts the surrounding stream.
interface Unmarshaler #
interface Unmarshaler {
mut:
from_cbor(data []u8) !
}
Unmarshaler is the reverse: given the bytes of one CBOR data item, populate the receiver. The slice is already trimmed to exactly one item by the generic decoder.
Implementers use a mut receiver:
pub fn (mut ip Ipv4) from_cbor(data []u8) ! { ... }
type Value #
type Value = Array
| Bool
| Bytes
| FloatNum
| IntNum
| Map
| Null
| Simple
| Tag
| Text
| Undefined
fn (Value) is_nil #
fn (v &Value) is_nil() bool
is_nil returns true if v is the CBOR null value.
fn (Value) is_undefined #
fn (v &Value) is_undefined() bool
is_undefined returns true if v is the CBOR undefined value.
fn (Value) as_int #
fn (v &Value) as_int() ?i64
as_int returns the value as an i64 when it fits, or none otherwise. Returns none for FloatNum, Text, etc.
CBOR negative integers represent -1 - magnitude, so magnitude 2^63 - 1 maps to i64::min and magnitude 2^63 would map to -2^63 - 1 — outside i64 range — hence the strict ">" cutoff for negatives. Use as_uint plus the negative flag to recover the full -2^64..2^64-1 CBOR range.
fn (Value) as_uint #
fn (v &Value) as_uint() ?u64
as_uint returns the value as a u64 if it's a non-negative integer, else none.
fn (Value) as_float #
fn (v &Value) as_float() ?f64
as_float returns the f64 value, or none if v isn't a FloatNum.
fn (Value) as_bool #
fn (v &Value) as_bool() ?bool
as_bool returns the boolean value, or none if v isn't a Bool.
fn (Value) as_string #
fn (v &Value) as_string() ?string
as_string returns the text-string value, or none if v isn't Text.
fn (Value) as_bytes #
fn (v &Value) as_bytes() ?[]u8
as_bytes returns the byte-string payload, or none if v isn't Bytes.
fn (Value) as_array #
fn (v &Value) as_array() ?[]Value
as_array returns the elements of an Array, or none.
fn (Value) as_map #
fn (v &Value) as_map() ?[]MapPair
as_map returns the pairs of a Map, or none.
fn (Value) as_tag #
fn (v &Value) as_tag() ?(u64, Value)
as_tag returns (number, content) of a Tag, or none.
fn (Value) get #
fn (v &Value) get(key string) ?Value
get does a linear lookup of a string-keyed entry in a Map. O(n) — for hot paths decode into a typed struct or map[string]V.
fn (Value) at #
fn (v &Value) at(index int) ?Value
at returns the element at index of an Array.
fn (Value) len #
fn (v &Value) len() int
len returns the length of an Array, Map, Text, or Bytes value, or 0.
enum FloatBits #
enum FloatBits as u8 {
@none = 0
half = 16
single = 32
double = 64
}
FloatBits records which IEEE 754 width the float was originally encoded at. The encoder honours this when re-emitting a Value, so round-tripping preserves the original byte width.
enum Kind #
enum Kind {
unsigned // major type 0
negative // major type 1
bytes // major type 2 (definite or indefinite)
text // major type 3 (definite or indefinite)
array_val // major type 4 (definite or indefinite)
map_val // major type 5 (definite or indefinite)
tag_val // major type 6
bool_val // simple 20/21
null_val // simple 22
undefined // simple 23
simple_val // other simple values
float_val // half/single/double
break_code // 0xff outside a definite header
}
Kind classifies the next item without consuming it. Useful to branch before committing to a typed read.
struct Array #
struct Array {
pub mut:
elements []Value
}
Array holds the elements of a CBOR array (major type 4).
struct Bool #
struct Bool {
pub:
value bool
}
Bool is the wrapped form of CBOR true/false (simple values 20/21).
struct Bytes #
struct Bytes {
pub mut:
data []u8
}
Bytes is a CBOR byte string (major type 2).
struct DecodeOpts #
struct DecodeOpts {
pub:
max_depth int = 256
max_stream_bytes int // 0 = unbounded for stream readers
validate_utf8 bool = true
deny_unknown_fields bool // struct decode rejects unmapped keys
deny_duplicate_keys bool // Map decode rejects repeated keys
allow_trailing_bytes bool // accept extra bytes after the top-level item
}
DecodeOpts tunes the decoder. Defaults are conservative: UTF-8 is validated, depth is capped to fend off stack-blow-up payloads, and duplicate map keys are tolerated (callers that need detection turn deny_duplicate_keys on).
struct EncodeOpts #
struct EncodeOpts {
pub:
initial_cap int = 64
canonical bool // sort map keys, definite-length only
self_describe bool // prepend tag 55799 (`d9 d9 f7`)
// validate_utf8 makes encode[T] reject V `string` payloads that
// contain non-UTF-8 bytes. Off by default to match the conventional
// V invariant ("strings are UTF-8") and avoid paying for validation
// on hot paths. Turn on at trust boundaries when callers may build
// strings from raw bytes (e.g. `bytestr()`), so the wire stays
// round-trip-safe against the strict-by-default decoder.
validate_utf8 bool
}
EncodeOpts tunes the encoder. Defaults yield RFC 8949 preferred serialisation: floats shrink to the shortest IEEE 754 width that preserves their value, headers use the shortest length encoding.
Setting canonical = true additionally sorts map keys per RFC 8949 §4.2.1 (deterministic encoding) — useful for hashing/signing.
struct FloatNum #
struct FloatNum {
pub:
value f64
bits FloatBits = .@none
}
FloatNum is a CBOR floating-point value (major type 7, additional info 25/26/27). bits records the wire width for fidelity on re-encoding; the default .@none lets the encoder pick the shortest IEEE 754 width that preserves the value (RFC 8949 §4.2.2 preferred serialisation), so hand-built FloatNum literals don't accidentally lock in 8-byte output.
struct IntNum #
struct IntNum {
pub:
negative bool
magnitude u64
}
IntNum holds the full unsigned/negative CBOR integer range. CBOR allows values from -(2^64) to 2^64-1, which exceeds either i64 or u64 alone, so the sign bit is split out and the magnitude carried as u64.
for unsigned: negative=false, magnitude=value for negative: negative=true, magnitude=encoded_argument actual integer = -1 - i64(magnitude) (when it fits i64)
struct IntRangeError #
struct IntRangeError {
Error
pub:
pos int
target string
value string
}
IntRangeError fires when a decoded integer doesn't fit the target type.
fn (IntRangeError) msg #
fn (e &IntRangeError) msg() string
msg formats an IntRangeError for IError.msg().
struct InvalidUtf8Error #
struct InvalidUtf8Error {
Error
pub:
pos int
}
InvalidUtf8Error fires when a text-string payload isn't valid UTF-8 and the decoder is configured to validate strings.
fn (InvalidUtf8Error) msg #
fn (e &InvalidUtf8Error) msg() string
msg formats an InvalidUtf8Error for IError.msg().
struct MalformedError #
struct MalformedError {
Error
pub:
pos int
reason string
}
MalformedError fires when the byte stream violates RFC 8949 well-formedness.
fn (MalformedError) msg #
fn (e &MalformedError) msg() string
msg formats a MalformedError for IError.msg().
struct Map #
struct Map {
pub mut:
pairs []MapPair
}
Map holds the ordered key/value pairs of a CBOR map (major type 5).
struct MapPair #
struct MapPair {
pub:
key Value
value Value
}
MapPair represents one key/value entry in a CBOR map. CBOR allows any data item as a key, so we keep an ordered list of pairs rather than using V's map[K]V.
struct MaxDepthError #
struct MaxDepthError {
Error
pub:
pos int
max_depth int
}
MaxDepthError fires when nested arrays/maps exceed the configured cap.
fn (MaxDepthError) msg #
fn (e &MaxDepthError) msg() string
msg formats a MaxDepthError for IError.msg().
struct Null #
struct Null {}
Null is the wrapped form of CBOR null (simple value 22).
struct Packer #
struct Packer {
pub mut:
buf []u8
opts EncodeOpts
mut:
indef_string_open bool // top of the indef "stack" is text or bytes
indef_other_depth int // count of currently open indef arrays/maps
}
Packer accumulates CBOR bytes into an internal buffer. Use bytes() to retrieve the wire output, or reset() to reuse the buffer for the next message — that's the cheapest way to emit many small frames.
indef_string_open and indef_other_depth track open indefinite-length items so the encoder can reject malformed compositions: nested indef strings, indef array/map inside an indef string (RFC 8949 §3.2.3), or a stray break code.
fn (Packer) bytes #
fn (mut p Packer) bytes() []u8
bytes returns the encoded buffer. The returned slice aliases the Packer's storage — clone it if you keep using the Packer. This is a low-level accessor that does NOT verify the buffer holds a complete item; if you opened an indefinite-length container without closing it, the bytes will be malformed. Use pack_to (or encode[T]) for the validated path, or call is_complete() yourself.
fn (Packer) is_complete #
fn (p &Packer) is_complete() bool
is_complete reports whether the buffer holds a sequence of fully closed items. False while an indefinite-length array, map, text, or bytes container is still open (waiting for pack_break).
fn (Packer) pack #
fn (mut p Packer) pack[T](val T) !
pack encodes val into the packer's buffer using compile-time dispatch.
fn (Packer) pack_array_header #
fn (mut p Packer) pack_array_header(n u64)
pack_array_header writes the prefix for a definite-length array.
fn (Packer) pack_array_indef #
fn (mut p Packer) pack_array_indef() !
pack_array_indef opens an indefinite-length array. Close with pack_break.
fn (Packer) pack_bool #
fn (mut p Packer) pack_bool(v bool)
pack_bool emits the simple value 20 (false) or 21 (true).
fn (Packer) pack_break #
fn (mut p Packer) pack_break() !
pack_break writes the break stop code 0xff that terminates the most recently opened indefinite-length item. Errors when no item is open (the byte 0xff is otherwise reserved and emitting one would corrupt the stream).
fn (Packer) pack_bytes #
fn (mut p Packer) pack_bytes(b []u8)
pack_bytes writes a byte string (major type 2).
fn (Packer) pack_bytes_indef #
fn (mut p Packer) pack_bytes_indef() !
pack_bytes_indef opens an indefinite-length byte string. Each chunk must be a definite-length byte string; close with pack_break.
fn (Packer) pack_float #
fn (mut p Packer) pack_float(v f64)
pack_float emits the shortest IEEE 754 width that preserves the value, per RFC 8949 §4.2.2. NaN serialises as the canonical quiet NaN (0xf97e00), not the original payload.
fn (Packer) pack_float16_bits #
fn (mut p Packer) pack_float16_bits(bits u16)
pack_float16_bits always emits a 2-byte IEEE 754 float.
fn (Packer) pack_float32 #
fn (mut p Packer) pack_float32(v f32)
pack_float32 always emits a 4-byte IEEE 754 float.
fn (Packer) pack_float64 #
fn (mut p Packer) pack_float64(v f64)
pack_float64 always emits an 8-byte IEEE 754 float.
fn (Packer) pack_int #
fn (mut p Packer) pack_int(v i64)
pack_int picks the right major type for a signed integer. For values below i64.min that can still fit -1-u64, prefer pack_negative_arg.
fn (Packer) pack_map_header #
fn (mut p Packer) pack_map_header(n u64)
pack_map_header writes the prefix for a definite-length map. The argument is the number of pairs, not items.
fn (Packer) pack_map_indef #
fn (mut p Packer) pack_map_indef() !
pack_map_indef opens an indefinite-length map. Close with pack_break.
fn (Packer) pack_negative_arg #
fn (mut p Packer) pack_negative_arg(arg u64)
pack_negative_arg writes a major type 1 value where the encoded argument is arg and the represented integer is -1 - arg. Lets you emit values down to -2^64 (the lower bound of CBOR negative ints).
fn (Packer) pack_null #
fn (mut p Packer) pack_null()
pack_null emits CBOR null (simple value 22, byte 0xf6).
fn (Packer) pack_raw #
fn (mut p Packer) pack_raw(raw RawMessage) !
pack_raw appends a RawMessage's bytes to the Packer without re-encoding. An empty RawMessage is rejected: emitting zero bytes would silently drop the slot when the value is a struct field or array element, shifting every subsequent item by one — almost always a caller bug.
fn (Packer) pack_simple #
fn (mut p Packer) pack_simple(v u8) !
pack_simple emits a CBOR simple value. Values 0..23 use the inline form, values 32..255 use the 1-byte trailer form. Values 24..31 are not well-formed per RFC 8949 §3.3 and are rejected here.
fn (Packer) pack_tag #
fn (mut p Packer) pack_tag(number u64)
pack_tag writes a tag header (major type 6). The next packed item is the tag's content.
fn (Packer) pack_text #
fn (mut p Packer) pack_text(s string)
pack_text writes a UTF-8 text string (major type 3). Single-shot reservation: the head + payload bytes are appended via one capacity check and one memcpy.
fn (Packer) pack_text_indef #
fn (mut p Packer) pack_text_indef() !
pack_text_indef opens an indefinite-length text string. Each chunk must be a definite-length text string; close with pack_break.
fn (Packer) pack_to #
fn (mut p Packer) pack_to(mut w io.Writer) !
pack_to is the streaming sibling of encode_to, for users who built their payload manually via the Packer API. Errors if any indefinite-length container is still open — emitting half-closed CBOR would produce a payload no decoder can parse.
fn (Packer) pack_uint #
fn (mut p Packer) pack_uint(v u64)
pack_uint emits a CBOR unsigned-integer (major type 0). Covers the full u64 range, including values above i64.max.
fn (Packer) pack_undefined #
fn (mut p Packer) pack_undefined()
pack_undefined emits CBOR undefined (simple value 23, byte 0xf7).
fn (Packer) pack_value #
fn (mut p Packer) pack_value(v Value) !
pack_value emits an arbitrary Value tree, honouring the original float width hint. Map keys are sorted when opts.canonical is set. Returns an error if the tree is malformed (e.g. a Tag with no content) — silently emitting a placeholder would corrupt round-trips.
fn (Packer) reserve #
fn (mut p Packer) reserve(n int)
reserve grows the buffer's capacity by at least n bytes. Useful before a string/binary write of known length to skip per-byte growth.
fn (Packer) reset #
fn (mut p Packer) reset()
reset clears the buffer for reuse. The capacity is preserved, so this is the fast path for high-throughput senders.
struct RawMessage #
struct RawMessage {
pub mut:
data []u8
}
RawMessage holds the byte-exact encoding of one CBOR data item as it appeared on the wire. Useful for caching/forwarding code that wants to defer decoding of a nested field.
struct Envelope { id int payload cbor.RawMessage // bytes preserved as-is }
raw := cbor.decodecbor.RawMessage! back := cbor.encode(raw, cbor.EncodeOpts{})! // identical bytes
struct Simple #
struct Simple {
pub:
value u8
}
Simple is the catch-all for major type 7 simple values 0..255 not otherwise covered by Bool/Null/Undefined.
struct Tag #
struct Tag {
pub:
number u64
content_box []Value
}
Tag wraps a tagged data item (major type 6). The content is stored in a one-element slice rather than as a &Value reference: V can box and recurse a sumtype through a slice, while a direct &Value field requires manual heap allocation. Use tag.content() to access it.
fn (Tag) content #
fn (t &Tag) content() Value
content returns the Value enclosed by a Tag, or Null{} if missing.
struct Text #
struct Text {
pub:
value string
}
Text is a CBOR text string (major type 3, valid UTF-8).
struct TypeMismatchError #
struct TypeMismatchError {
Error
pub:
pos int
expected string
got u8 // initial byte
}
TypeMismatchError fires when a typed read finds a different major type.
fn (TypeMismatchError) msg #
fn (e &TypeMismatchError) msg() string
msg formats a TypeMismatchError for IError.msg().
struct Undefined #
struct Undefined {}
Undefined is the wrapped form of CBOR undefined (simple value 23).
struct UnexpectedEofError #
struct UnexpectedEofError {
Error
pub:
pos int // position at which the read began
need i64 // bytes the decoder was trying to read
remaining int // bytes actually available
}
UnexpectedEofError fires when the decoder runs past the end of its input. need is i64 so it can represent the full CBOR length range (which is u64 on the wire); huge values are clamped to i64::max for reporting.
fn (UnexpectedEofError) msg #
fn (e &UnexpectedEofError) msg() string
msg formats an UnexpectedEofError for IError.msg().
struct UnknownFieldError #
struct UnknownFieldError {
Error
pub:
pos int
name string
}
UnknownFieldError fires when a struct decoded with deny_unknown_fields encounters an unmapped key.
fn (UnknownFieldError) msg #
fn (e &UnknownFieldError) msg() string
msg formats an UnknownFieldError for IError.msg().
struct Unpacker #
struct Unpacker {
pub mut:
data []u8
pos int
opts DecodeOpts
}
Unpacker walks a CBOR byte slice. Operates non-allocating where possible; strings and bytes returned by unpack_text / unpack_bytes always own their storage so they outlive the input buffer.
fn (Unpacker) done #
fn (u &Unpacker) done() bool
done reports whether the unpacker has consumed every byte.
fn (Unpacker) expect_break #
fn (mut u Unpacker) expect_break() !
expect_break consumes a single 0xff break code; errors otherwise.
fn (Unpacker) peek_break #
fn (u &Unpacker) peek_break() bool
peek_break reports whether the next byte is the break stop code.
fn (Unpacker) peek_kind #
fn (u &Unpacker) peek_kind() !Kind
peek_kind classifies the next item without consuming any input.
fn (Unpacker) remaining #
fn (u &Unpacker) remaining() int
remaining returns the number of unread bytes.
fn (Unpacker) skip_value #
fn (mut u Unpacker) skip_value() !
skip_value advances past one complete CBOR value without allocating. Honours the depth cap so adversarial deeply-nested input cannot blow the stack.
fn (Unpacker) unpack #
fn (mut u Unpacker) unpack[T]() !T
unpack reads one CBOR value from the buffer and converts it to T.
fn (Unpacker) unpack_array_header #
fn (mut u Unpacker) unpack_array_header() !i64
unpack_array_header reads the prefix of an array. Returns the count for definite-length arrays, or -1 for indefinite-length arrays (the caller then loops until peek_kind() == .break_code and consumes the break with expect_break).
fn (Unpacker) unpack_bool #
fn (mut u Unpacker) unpack_bool() !bool
unpack_bool reads a CBOR boolean (simple 20/21). Position is rolled back on a type mismatch so callers can branch on peek_kind and try a different read.
fn (Unpacker) unpack_bytes #
fn (mut u Unpacker) unpack_bytes() ![]u8
unpack_bytes reads a definite or indefinite-length byte string. The returned slice is a clone, safe to retain after the unpacker is freed.
fn (Unpacker) unpack_float #
fn (mut u Unpacker) unpack_float() !f64
unpack_float reads a CBOR float of any width (half/single/double) and returns it as f64.
fn (Unpacker) unpack_int #
fn (mut u Unpacker) unpack_int() !i64
unpack_int reads any CBOR integer (major type 0 or 1) into i64. Errors when the magnitude exceeds i64 range; use unpack_int_full to pull values as u64 with a separate sign flag.
fn (Unpacker) unpack_int_full #
fn (mut u Unpacker) unpack_int_full() !(bool, u64)
unpack_int_full returns (negative, magnitude). For unsigned values negative=false and magnitude is the raw u64. For negative values negative=true and magnitude is the encoded argument (the integer itself is -1 - magnitude).
fn (Unpacker) unpack_map_header #
fn (mut u Unpacker) unpack_map_header() !i64
unpack_map_header reads the prefix of a map. Returns pair count or -1 for indefinite-length maps.
fn (Unpacker) unpack_null #
fn (mut u Unpacker) unpack_null() !
unpack_null consumes a CBOR null (0xf6) or errors with type mismatch. Position is rolled back on mismatch (same convention as unpack_bool).
fn (Unpacker) unpack_raw #
fn (mut u Unpacker) unpack_raw() !RawMessage
unpack_raw captures the bytes of the next value without building a Value tree. Returns an owned clone, safe to outlive the unpacker.
fn (Unpacker) unpack_simple #
fn (mut u Unpacker) unpack_simple() !u8
unpack_simple reads a simple value (0..255). Bool/null/undefined are also simple values; this method returns the raw u8.
fn (Unpacker) unpack_tag #
fn (mut u Unpacker) unpack_tag() !u64
unpack_tag reads a tag header and returns the tag number. The caller must follow up by reading the tag content. Position is rolled back on any error so callers can branch on peek_kind and try a different read.
fn (Unpacker) unpack_text #
fn (mut u Unpacker) unpack_text() !string
unpack_text reads a definite or indefinite-length text string. The returned string owns its bytes (it's a clone of the input slice). UTF-8 validation runs unless DecodeOpts.validate_utf8 is false.
fn (Unpacker) unpack_uint #
fn (mut u Unpacker) unpack_uint() !u64
unpack_uint reads a non-negative integer (major type 0). Errors on negatives, floats, or other major types. Position is rolled back on any error so callers can branch on peek_kind and try a different read (same convention as unpack_bool / unpack_text).
fn (Unpacker) unpack_value #
fn (mut u Unpacker) unpack_value() !Value
unpack_value materialises one CBOR data item as a Value.
- README
- Constants
- fn decode
- fn decode_from
- fn encode
- fn encode_to
- fn encode_value
- fn new_bytes
- fn new_float
- fn new_int
- fn new_negative
- fn new_packer
- fn new_tag
- fn new_text
- fn new_uint
- fn new_unpacker
- fn FloatBits.from
- fn Kind.from
- interface Marshaler
- interface Unmarshaler
- type Value
- enum FloatBits
- enum Kind
- struct Array
- struct Bool
- struct Bytes
- struct DecodeOpts
- struct EncodeOpts
- struct FloatNum
- struct IntNum
- struct IntRangeError
- struct InvalidUtf8Error
- struct MalformedError
- struct Map
- struct MapPair
- struct MaxDepthError
- struct Null
- struct Packer
- fn bytes
- fn is_complete
- fn pack
- fn pack_array_header
- fn pack_array_indef
- fn pack_bool
- fn pack_break
- fn pack_bytes
- fn pack_bytes_indef
- fn pack_float
- fn pack_float16_bits
- fn pack_float32
- fn pack_float64
- fn pack_int
- fn pack_map_header
- fn pack_map_indef
- fn pack_negative_arg
- fn pack_null
- fn pack_raw
- fn pack_simple
- fn pack_tag
- fn pack_text
- fn pack_text_indef
- fn pack_to
- fn pack_uint
- fn pack_undefined
- fn pack_value
- fn reserve
- fn reset
- struct RawMessage
- struct Simple
- struct Tag
- struct Text
- struct TypeMismatchError
- struct Undefined
- struct UnexpectedEofError
- struct UnknownFieldError
- struct Unpacker
- fn done
- fn expect_break
- fn peek_break
- fn peek_kind
- fn remaining
- fn skip_value
- fn unpack
- fn unpack_array_header
- fn unpack_bool
- fn unpack_bytes
- fn unpack_float
- fn unpack_int
- fn unpack_int_full
- fn unpack_map_header
- fn unpack_null
- fn unpack_raw
- fn unpack_simple
- fn unpack_tag
- fn unpack_text
- fn unpack_uint
- fn unpack_value