cbor.cr
cbor.cr
a lightweight, dependency-free, high-performance and RFC 8949 compliant CBOR (Concise Binary Object Representation) implementation for the Crystal programming language.
Key Features
- Full RFC 8949 Compliance: Supports all Major Types (0 to 7).
- Streaming Support: Encode and decode directly to/from any
IO(files, sockets, memory) without loading entire payloads into RAM. - Semantic Tags: Native support for CBOR Tags (Major Type 6) to add metadata to your data structures.
- Type Safety: Seamless integration with Crystal’s type system using the
CBOR::Valuealias. - Diagnostic & Debugging Tools: Utilities for human-readable CBOR diagnostic notation and hex inspection to visualize hierarchy for low-level debugging.
Roadmap & Future Enhancements
-
CBOR::SerializableModule: Implement a high-level API similar toJSON::Serializablefor seamless object mapping using class annotations. - Extensible Tag Registry: Develop a plugin system to register custom converters for specific CBOR Tags, enabling automatic conversion between custom types and binary data.
Installation
Add the library to your shard.yml:
dependencies:
cbor:
github: mamiysr/cbor.cr
Then, install the dependencies:
shards install
Usage
Basic Encoding and Decoding
Transforming data structures to binary and back is straightforward.
require "cbor"
# Create a data structure
data = {
"name" => "Crystal",
"version" => 1.18,
"active" => true,
"tags" => [1, 2, 3]
}
# Encode: Hash -> Bytes
encoded = CBOR.encode(data)
puts "Encoded size: #{encoded.size} bytes"
# Decode: Bytes -> CBOR::Value -> Hash
decoded = CBOR.decode(encoded).as(Hash)
puts decoded["name"] # => "Crystal"
Streaming (IO-Based Processing)
For large datasets, you can process data chunk-by-chunk using Crystal's IO system to keep memory usage low.
# Write to a file (Encoding)
File.open("data.cbor", "w") do |file|
CBOR.encode({"sensor_id" => 12345}, file)
end
# Read from a file (Decoding)
File.open("data.cbor", "r") do |file|
decoded = CBOR.decode(file)
puts decoded
end
Working with CBOR Tags
Tags are used to provide extra semantic meaning to data (e.g., indicating a string is actually a Date or a UUID).
# Manually create a Tag (e.g., Tag 1 for Date/Time)
date_tag = CBOR::Tag.new(1_u64, "2026-01-14")
encoded = CBOR.encode(date_tag)
decoded = CBOR.decode(encoded).as(CBOR::Tag)
puts "Tag ID: #{decoded.id}" # => 1
puts "Content: #{decoded.content}" # => "2026-01-14"
Diagnostic & Debugging
.diagnose provides JSON like human-readable text representation of encoded binary data for quick verification, .inspect_hex performs deep structural analysis to visualize exactly how each byte maps to the data hierarchy for low-level debugging.
data = {
"name" => "Crystal",
"version" => 1.18,
"active" => true,
"tags" => [1, 2, 3]
}
encoded = CBOR.encode(data)
pp CBOR.inspect_hex(encoded)
# Offset | Hex Bytes | Structure
# -------|------------|----------------
# 0000 | A4 | Map(size: 4)
# 0001 | 64 6E 61 6D_ | String(4): "name"
# 0006 | 67 43 72 79_ | String(7): "Crystal"
# 000E | 67 76 65 72_ | String(7): "version"
# 0016 | FB 3F F2 E1_ | Float64: 1.18
# 001F | 66 61 63 74_ | String(6): "active"
# 0026 | F5 | Simple: true
# 0027 | 64 74 61 67_ | String(4): "tags"
# 002C | 83 | Array(size: 3)
# 002D | 01 | Positive Int: 1
# 002E | 02 | Positive Int: 2
# 002F | 03 | Positive Int: 3
puts CBOR.diagnose(encoded) # => {"name": "Crystal", "version": 1.18, "active": true, "tags": [1, 2, 3]}
Contributing
- Fork it (https://github.com/mamiysr/cbor.cr/fork)
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new Pull Request
License
MIT License.
cbor.cr
- 0
- 0
- 0
- 0
- 0
- about 18 hours ago
- January 13, 2026
MIT License
Thu, 15 Jan 2026 08:05:42 GMT