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
Value is the dynamic representation of any CBOR data item. Use it when the schema isn't known at compile time, when you need to inspect tags, or when keys aren't strings:
v := cbor.decodecbor.Value! match v { cbor.Text { println(v.value) } else { ... } }
For known schemas prefer decode[YourStruct] — it's faster and avoids the heap allocations of building a Value tree.
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