CBOR Encoding

View Source

Binary serialization for efficient data transfer using CBOR (Concise Binary Object Representation).

Overview

CBOR is a binary data format that is:

  • More compact than JSON
  • Faster to parse
  • Supports binary data natively
  • Self-describing

QuickJS uses its native CBOR implementation for encoding and decoding.

Basic Usage

Encoding

Convert Erlang values to CBOR binary:

{ok, Ctx} = quickjs:new_context().

%% Encode simple values
{ok, Bin1} = quickjs:cbor_encode(Ctx, 42).
{ok, Bin2} = quickjs:cbor_encode(Ctx, <<"hello">>).
{ok, Bin3} = quickjs:cbor_encode(Ctx, true).

%% Encode complex structures
{ok, Bin4} = quickjs:cbor_encode(Ctx, #{
    name => <<"Alice">>,
    age => 30,
    tags => [<<"admin">>, <<"user">>]
}).

Decoding

Convert CBOR binary back to Erlang values:

{ok, 42} = quickjs:cbor_decode(Ctx, Bin1).
{ok, <<"hello">>} = quickjs:cbor_decode(Ctx, Bin2).
{ok, true} = quickjs:cbor_decode(Ctx, Bin3).

{ok, #{
    <<"name">> := <<"Alice">>,
    <<"age">> := 30,
    <<"tags">> := [<<"admin">>, <<"user">>]
}} = quickjs:cbor_decode(Ctx, Bin4).

Supported Types

Erlang TypeCBOR TypeNotes
integer()IntegerFull range supported
float()FloatIEEE 754 double
binary()Text stringUTF-8 encoded
true/falseBoolean
nullNull
undefinedUndefined
list()Array
map()Map

Roundtrip Example

{ok, Ctx} = quickjs:new_context().

Original = #{
    users => [
        #{id => 1, name => <<"Alice">>, active => true},
        #{id => 2, name => <<"Bob">>, active => false}
    ],
    metadata => #{
        version => <<"1.0">>,
        count => 2
    }
}.

%% Encode
{ok, Binary} = quickjs:cbor_encode(Ctx, Original).

%% Binary is compact
byte_size(Binary).  %% Much smaller than JSON

%% Decode
{ok, Decoded} = quickjs:cbor_decode(Ctx, Binary).

%% Values match (note: atom keys become binary keys)
#{<<"users">> := Users} = Decoded.

Use Cases

Inter-Process Communication

CBOR is ideal for sending data between Erlang processes and JavaScript:

%% Encode data in one context
{ok, Ctx1} = quickjs:new_context().
{ok, Binary} = quickjs:cbor_encode(Ctx1, large_data_structure()).

%% Decode in another context
{ok, Ctx2} = quickjs:new_context().
{ok, Data} = quickjs:cbor_decode(Ctx2, Binary).

File Storage

Store structured data efficiently:

save_config(Ctx, Config, Filename) ->
    {ok, Binary} = quickjs:cbor_encode(Ctx, Config),
    file:write_file(Filename, Binary).

load_config(Ctx, Filename) ->
    {ok, Binary} = file:read_file(Filename),
    quickjs:cbor_decode(Ctx, Binary).

Network Protocol

Use CBOR for wire protocols:

send_message(Ctx, Socket, Message) ->
    {ok, Binary} = quickjs:cbor_encode(Ctx, Message),
    Size = byte_size(Binary),
    gen_tcp:send(Socket, <<Size:32, Binary/binary>>).

receive_message(Ctx, Socket) ->
    {ok, <<Size:32>>} = gen_tcp:recv(Socket, 4),
    {ok, Binary} = gen_tcp:recv(Socket, Size),
    quickjs:cbor_decode(Ctx, Binary).

Performance

CBOR operations run on dirty schedulers to avoid blocking the Erlang VM:

%% These operations won't block other Erlang processes
{ok, _} = quickjs:cbor_encode(Ctx, very_large_structure()),
{ok, _} = quickjs:cbor_decode(Ctx, large_binary()).

Typical performance on modern hardware:

  • Encode: ~1,900 ops/sec for complex structures
  • Decode: ~1,900 ops/sec for complex structures
  • Roundtrip: ~1,850 ops/sec

Error Handling

%% Invalid CBOR binary
{error, _} = quickjs:cbor_decode(Ctx, <<"not valid cbor">>).

%% Invalid context
{error, invalid_context} = quickjs:cbor_encode(destroyed_ctx, data).