Skip to content
Concise Binary Object Representation (RFC 7049)
Elixir
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
lib
test
.formatter.exs
.gitignore
LICENSE.md
README.md
mix.exs
mix.lock

README.md

CBOR

Implementation of RFC 7049 CBOR (Concise Binary Object Representation) for Elixir.

This is a fork of excbor which modernizes the codebase, and makes decisions on handling data types that the original library had punted on.

Migrating from the previous version

This library is a fork of the no longer maintained excbor project.

For those migrating from previous versions of this library there are breaking changes that you should be aware of.

The module Cbor has been renamed to CBOR

CBOR.decode will return a three item tuple of the form {:ok, decoded, rest}, instead of returning the decoded object. In the wild there are APIs that concat CBOR objects together. The rest variable includes any leftover information from the decoding operation in case you need to decode multiple objects.

Atoms will be encoded/decoded as strings, except for the special case of :__undefined__ which has no direct translation to elixir but has semantic meaning in CBOR.

Elixir/Erlang does not have a concept of infinity, negative infinity or NaN. In order to encode or decode these values we will return a struct of the form %CBOR.Tag{tag: :float, value: (:inf|:"-inf"|:nan)}

If you want to encode a raw binary value, you can use the CBOR.Tag struct with a tag of :bytes and the binary as the :value field.

Installation

def deps do
  [
    {:cbor, "~> 1.0.0"}
  ]
end

Usage

This library follows the standard API for CBOR libraries by exposing two methods on the CBOR module encode/1 and decode/1.

Encoding

iex(1)> CBOR.encode([1, [2, 3]])
<<130, 1, 130, 2, 3>>

Decoding

iex(2)> CBOR.decode(<<130, 1, 130, 2, 3>>)
{:ok, [1, [2, 3]], ""}

Design Notes

Given that Elixir has more available data types than are supported in CBOR, decisions were made so that encoding complex data structures succeed without throwing errors. My thoughts are collected below so you can understand why encoding and decoding of a value does not necessarily return exactly the same value.

Atoms

The only atoms that will be directly encoded are true, false nil and __undefined__. Every other atom will be converted to a string before being encoded. We surround undefined with double underscores so that you only encode an undefined value when you clearly intend to do so.

Keyword List, MapSet, Range, Tuple

All of the above data structures are converted to Lists before being encoded. This ensures that there is no data lost when encoding and decoding.

NaiveDateTime

NaiveDateTime will be treated as if they are UTC.

Special Values

Elixir and erlang have no concept of infinity, negative infinity and NaN. If you want to encode those values, we have a special struct CBOR.Tag which you can use to represent those values.

%CBOR.Tag{tag: :float, value: :inf}

%CBOR.Tag{tag: :float, value: :"-inf"}

%CBOR.Tag{tag: :float, value: :nan}

CBOR.Tag is also useful if you want to extend CBOR for internal applications

Custom Encoding

If you want to encode something that is not supported out of the box you can implement the CBOR.Encoder protocol for the module. You only have to implement a single encode_into/2 function. An example for encoding a Money struct is given below.

defimpl CBOR.Encoder, for: Money do
  def encode_into(money, acc) do
    money |> Money.to_string() |> CBOR.Encoder.encode_into(acc)
  end
end

Documentation

Documentation can be generated with ExDoc and published on HexDocs. Once published, the docs can be found at https://hexdocs.pm/cbor.

You can’t perform that action at this time.