defmodule BorshEx do @moduledoc """ Elixir implementation of Binary Object Representation Serializer for Hashing ([borsh](borsh.io)) ## Usage Define schema using `BorshEx.Schema` defmodule SubData do use BorshEx.Schema defstruct address: nil borsh_schema do field :address, "string" end end defmodule Data do use BorshEx.Schema defstruct name: nil borsh_schema do field :id, "u16" field :sub_data, SubData end end Once schema is define, we are able to serialize a struct into a binary or deserialize to a struct. iex> data = %Data{id: 45, sub_data: %SubData{address: "Hello world!"}} %Data{id: 45, sub_data: %SubData{address: "Hello world!"}} iex> bistring = Data.serialize(data) <<45, 0, 12, 0, 0, 0, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33>> iex> data = Data.deserialize(bitstring) {:ok, %Data{id: 45, sub_data: %SubData{address: "Hello world!"}}} In some case the bitstring is longer than necessary, some bytes are not used iex> bitstring = <<45, 0, 12, 0, 0, 0, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 5, 0>> <<45, 0, 12, 0, 0, 0, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33, 10, 5, 0>> iex> data = Data.deserialize(bitstring) {:error, %Data{id: 45, sub_data: %SubData{address: "Hello world!"}}, <<5, 0>>} `<<5, 0>>` returned are unused bytes. ## Basic types | type | example | | ------------------------- | --------------------- | | `u8`, `u16`, `u32`, `u64` | `field :id, "u8"` | | `i8`, `i16`, `i32`, `i64` | `field :id, "i8"` | | `boolean` | `field :id, "bool"` | | `string` | `field :id, "string"` | | `struct` | `field :id, MyStruct` | ## Complex types All types can be used in a more complex one ### Array An array can have a fixed size # ids is a list of 32 `u16` values # sub_data is a list of 32 Subdata strut borsh_schema do field :ids, {"array", {"u16", 32}} field :sub_data, {"array", {Subdata, 32}} end Or variable length # ids is a list `u16` value # sub_data is a list of Subdata strut borsh_schema do field :ids, {"array", "u16"} field :sub_data, {"array", {Subdata, 32}} end ### Option a field can be optional # if name can be nil or a string borsh_schema do field :name, {"option", "string"} end iex> data = %Data{name: nil} %Data{name: nil} iex> Data.serialize(data) <<0>> iex> data = %Data{name: "Hello"} %Data{name: "Hello"} iex> Data.serialize(data) <<1, 5, 0, 0, 0, 72, 101, 108, 108, 111>> """ end