Borsh for Ruby

May 12, 2025 ยท View on GitHub

License Compatibility Package Documentation

Borsh.rb is a Ruby library for encoding and decoding data in the Borsh binary serialization format designed for security-critical projects where consistency, safety, and performance matter.

โœจ Features

  • 100% pure Ruby with zero dependencies and no bloat.
  • Implements the full Borsh specification with support for every type.
  • Supports both in-memory buffers and I/O streams for serialization.
  • Provides a simple and intuitive API for reading and writing data.
  • Provides a convenient buffer interface layered on top of StringIO.
  • Supports customizable serialization using the #to_borsh protocol.
  • Plays nice with others: entirely contained in the Borsh module.
  • 100% free and unencumbered public domain software.

๐Ÿ› ๏ธ Prerequisites

โฌ‡๏ธ Installation

Installation via RubyGems

gem install borsh

๐Ÿ‘‰ Examples

Importing the library

require 'borsh'

Writing to an in-memory buffer

serialized_data = Borsh::Buffer.open do |buf|
  # Primitive types:
  buf.write_bool(true)
  buf.write_u8(255)
  buf.write_i32(-12345)
  buf.write_u128(2**100)
  buf.write_i128(-2**100)
  buf.write_f64(3.14159)
  buf.write_string("Hello, Borsh!")

  # Fixed-size array:
  buf.write_array([1, 2, 3])

  # Dynamic-sized array (array with a length prefix):
  buf.write_vector(['a', 'b', 'c'])

  # Set of integers:
  buf.write_set(Set.new([1, 2, 3]))

  # Map with string keys and integer values:
  buf.write_map({a: 1, b: 2})
end

Reading from an in-memory buffer

Borsh::Buffer.new(serialized_data) do |buf|
  # Primitive types:
  bool_val = buf.read_bool             # => true
  u8_val = buf.read_u8                 # => 255
  i32_val = buf.read_i32               # => -12345
  u128_val = buf.read_u128             # => 2**100
  i128_val = buf.read_i128             # => -2**100
  f64_val = buf.read_f64               # => 3.14159
  string_val = buf.read_string         # => "Hello, Borsh!"

  # Fixed-size array:
  array = buf.read_array(:i64, 3)      # => [1, 2, 3]

  # Dynamic-sized array (array with a length prefix):
  vector = buf.read_vector(:string)    # => ['a', 'b', 'c']

  # Set of integers:
  set = buf.read_set(:i64)             # => Set.new([1, 2, 3])

  # Map with string keys and integer values:
  map = buf.read_map(:string, :i64)    # => {'a' => 1, 'b' => 2}
end

Writing to any output stream

$stdout.extend(Borsh::Writable)
$stdout.write_string("Hello, world!")

Reading from any input stream

$stdin.extend(Borsh::Readable)
puts $stdin.read_string

๐Ÿ“š Reference

Informal TypeBorsh::WritableBorsh::Readable
nil/unitwrite_unit()read_unit()
booleanwrite_bool(x)read_bool()
u8 integerwrite_u8(n)read_u8()
u16 integerwrite_u16(n)read_u16()
u32 integerwrite_u32(n)read_u32()
u64 integerwrite_u64(n)read_u64()
u128 integerwrite_u128(n)read_u128()
i8 integerwrite_i8(n)read_i8()
i16 integerwrite_i16(n)read_i16()
i32 integerwrite_i32(n)read_i32()
i64 integerwrite_i64(n)read_i64()
i128 integerwrite_i128(n)read_i128()
f32 floatwrite_f32(f)read_f32()
f64 floatwrite_f64(f)read_f64()
stringwrite_string(x)read_string()
arraywrite_array(x)read_array(element_type, count)
vectorwrite_vector(x)read_vector(element_type)
setwrite_set(x)read_set(element_type)
map/hashwrite_map(x)read_map(key_type, value_type)
optionwrite_option(x)read_option(element_type)
resultwrite_result([ok, value])read_result(ok_type, err_type)
enumwrite_enum([ordinal, value])read_enum(variants)
structwrite_struct(x)read_struct(struct_class)

๐Ÿ‘จโ€๐Ÿ’ป Development

git clone https://github.com/dryruby/borsh.rb.git

Share on X Share on Reddit Share on Hacker News Share on Facebook Share on LinkedIn