0b4f68c Upgrade to latest crystal, release 1.0.0
~arestifo pushed to ~arestifo/crystal-cbor git
0b4f68c Upgrade to latest crystal, release 1.0.0
~arestifo pushed to ~arestifo/crystal-cbor git
This library implements the RFC7049: Concise Binary Object Representation (CBOR) in Crystal.
require "cbor"
class Location
include CBOR::Serializable
@[CBOR::Field(key: "lat")]
property latitude : Float64
@[CBOR::Field(key: "lng")]
property longitude : Float64
end
class House
include CBOR::Serializable
property address : String
property location : Location?
end
data = {
"address" => "Crystal Road 1234",
"location" => { "lat" => 12.3, "lng" => 34.5 }
}
cbor = data.to_cbor # => Bytes[...]
CBOR::Diagnostic.to_s(cbor) # => {"address": "Crystal Road 1234", "location": {"lat": 12.3, "lng": 34.5}}
house = House.from_cbor(cbor)
house.address # => "Crystal Road 1234"
house.location # => #<Location:0x10cd93d80 @latitude=12.3, @longitude=34.5>
bytes = house.to_cbor # => Bytes[...]
CBOR::Diagnostic.to_s(bytes) # => {"address": "Crystal Road 1234", "location": {"lat": 12.3, "lng": 34.5}}
data_array = [data]
cbor_array = data_array.to_cbor # => Bytes[...]
CBOR::Diagnostic.to_s(cbor) # => [{"address": "Crystal Road 1234", "location": {"lat": 12.3, "lng": 34.5}}]}
houses = Array(House).from_cbor(cbor_array)
houses.size # => 1
bytes = houses.to_cbor # => Bytes[...]
CBOR::Diagnostic.to_s(bytes) # => [{"address": "Crystal Road 1234", "location": {"lat": 12.3, "lng": 34.5}}]
Add the dependency to your shard.yml
:
dependencies:
cbor:
git: https://git.sr.ht/~arestifo/crystal-cbor
Run shards install
Including CBOR::Serializable
will create #to_cbor
and self.from_cbor
methods
on the current class, and a constructor which takes a CBOR::Decoder
.
By default, these methods serialize into a cbor map containing the value of every instance variable, the keys being the instance variable name.
Most primitives and collections are supported as instance variable values (string,
integer, array, hash, etc.), along with objects which define to_cbor and a
constructor taking a CBOR::Decoder
.
Union types are also supported, including unions with nil
. If multiple types
in a union parse correctly, it is undefined which one will be chosen.
To change how individual instance variables are parsed and serialized,
the annotation CBOR::Field
can be placed on the instance variable.
Annotating property, getter and setter macros is also allowed.
require "cbor"
class A
include CBOR::Serializable
@[CBOR::Field(key: "my_key")]
getter a : Int32?
end
CBOR::Field
propertiestrue
skip this field in serialization and deserialization
(by default false
)from_cbor(CBOR::Decoder)
and
to_cbor(value, CBOR::Builder)
as class methods. Examples of converters are
Time::Format::RFC_333
and Time::EpochConverter
for Time
.true
, a @{{key}}_present
instance variable will be generated
when the key was present (even if it has a null
value), false
by defaulttrue
, emits a null
value for nilable property
(by default nulls are not emitted)true
, when the value is nil
, it is emitted as
undefined
(by default nil
are encoded as null
)Deserialization also respects default values of variables:
require "cbor"
struct A
include CBOR::Serializable
@a : Int32
@b : Float64 = 1.0
end
A.from_cbor({"a" => 1}.to_cbor) # => A(@a=1, @b=1.0)
CBOR::Serializable::Unmapped
If the CBOR::Serializable::Unmapped
module is included, unknown properties in
the CBOR document will be stored in a Hash(String, CBOR::Type)
.
On serialization, any keys inside cbor_unmapped
will be serialized and appended
to the current cbor map.
require "cbor"
struct A
include CBOR::Serializable
include CBOR::Serializable::Unmapped
@a : Int32
end
a = A.from_cbor({"a" => 1, "b" => 2}.to_cbor) # => A(@cbor_unmapped={"b" => 2}, @a=1)
bytes = a.to_cbor # => Bytes[...]
CBOR::Diagnostic.to_s(bytes) # => {"a": 1, "b": 2}
CBOR::Serializable::Options
supported properties:
true
, emits a null
value for all nilable properties
(by default nulls are not emitted)true
, emits a nil
value as undefined
(by default nil emits null
)require "cbor"
@[CBOR::Serializable::Options(emit_nulls: true)]
class A
include CBOR::Serializable
@a : Int32?
end
All the tags specified in section 2.4 of RFC 7049 are supported and the values are encoded in the respective Crystal types:
Time
BigInt
BigDecimal
The spec allows for the maximum length of arrays, string arrays and bytes array
to be a UInt64
.
While this library supports lengths expressed as a UInt64
, it must not exceed
Int32::MAX
.
If you're stuck and need help, if you have any questions, or if you simply want to stay up to date with the latest news and developments, you can subscribe to the crystal-cbor mailing list.
If you found an issue, you can open an issue on the ticket tracker.
The code is hosted on SourceHut and the development happens over the crystal-cbor mailing list.
For issues and feature requests, you can open and issue in the ticket tracker.
For code contributions You can send a patch to: ~arestifo/crystal-cbor@lists.sr.ht.
To learn how to use git send-email
, there is a great step-by-step tutorial
at git-send-email.io.
You might also want to read the mailing list etiquette.