Testnet is now LIVE at testnet.spacetimedb.com! NOTE: This is a testnet, and all data will be wiped periodically.

1.0 RC2

Login

SATN Binary Format (BSATN)

The Spacetime Algebraic Type Notation binary (BSATN) format defines how Spacetime AlgebraicValues and friends are encoded as byte strings.

Algebraic values and product values are BSATN-encoded for e.g., module-host communication and for storing row data in the database.

Notes on notation

In this reference, we give a formal definition of the format. To do this, we use inductive definitions, and define the following notation:

  • bsatn(x) denotes a function converting some value x to a list of bytes.
  • a: B means that a is of type B.
  • Foo(x) denotes extracting x out of some variant or type Foo.
  • a ++ b denotes concatenating two byte lists a and b.
  • bsatn(A) = bsatn(B) | ... | bsatn(Z) where B to Z are variants of A means that bsatn(A) is defined as e.g., bsatn(B), bsatn(C), .., bsatn(Z) depending on what variant of A it was.
  • [] denotes the empty list of bytes.

Values

At a glance

Type Description
AlgebraicValue A value whose type may be any AlgebraicType.
SumValue A value whose type is a SumType.
ProductValue A value whose type is a ProductType.
BuiltinValue A value whose type is a BuiltinType.

`AlgebraicValue`

The BSATN encoding of an AlgebraicValue defers to the encoding of each variant:

bsatn(AlgebraicValue) = bsatn(SumValue) | bsatn(ProductValue) | bsatn(BuiltinValue) 

`SumValue`

An instance of a SumType. SumValues are binary-encoded as bsatn(tag) ++ bsatn(variant_data) where tag: u8 is an index into the SumType.variants array of the value's SumType, and where variant_data is the data of the variant. For variants holding no data, i.e., of some zero sized type, bsatn(variant_data) = [].

`ProductValue`

An instance of a ProductType. ProductValues are binary encoded as:

bsatn(elems) = bsatn(elem_0) ++ .. ++ bsatn(elem_n) 

Field names are not encoded.

`BuiltinValue`

An instance of a BuiltinType. The BSATN encoding of BuiltinValues defers to the encoding of each variant:

bsatn(BuiltinValue)
    = bsatn(Bool)
    | bsatn(U8) | bsatn(U16) | bsatn(U32) | bsatn(U64) | bsatn(U128)
    | bsatn(I8) | bsatn(I16) | bsatn(I32) | bsatn(I64) | bsatn(I128)
    | bsatn(F32) | bsatn(F64)
    | bsatn(String)
    | bsatn(Array)
    | bsatn(Map)

bsatn(Bool(b)) = bsatn(b as u8)
bsatn(U8(x)) = [x]
bsatn(U16(x: u16)) = to_little_endian_bytes(x)
bsatn(U32(x: u32)) = to_little_endian_bytes(x)
bsatn(U64(x: u64)) = to_little_endian_bytes(x)
bsatn(U128(x: u128)) = to_little_endian_bytes(x)
bsatn(I8(x: i8)) = to_little_endian_bytes(x)
bsatn(I16(x: i16)) = to_little_endian_bytes(x)
bsatn(I32(x: i32)) = to_little_endian_bytes(x)
bsatn(I64(x: i64)) = to_little_endian_bytes(x)
bsatn(I128(x: i128)) = to_little_endian_bytes(x)
bsatn(F32(x: f32)) = bsatn(f32_to_raw_bits(x)) // lossless conversion
bsatn(F64(x: f64)) = bsatn(f64_to_raw_bits(x)) // lossless conversion
bsatn(String(s)) = bsatn(len(s) as u32) ++ bsatn(bytes(s))
bsatn(Array(a)) = bsatn(len(a) as u32)
               ++ bsatn(normalize(a)_0) ++ .. ++ bsatn(normalize(a)_n)
bsatn(Map(map)) = bsatn(len(m) as u32)
               ++ bsatn(key(map_0)) ++ bsatn(value(map_0))
               ..
               ++ bsatn(key(map_n)) ++ bsatn(value(map_n)) 

Where

  • f32_to_raw_bits(x) is the raw transmute of x: f32 to u32
  • f64_to_raw_bits(x) is the raw transmute of x: f64 to u64
  • normalize(a) for a: ArrayValue converts a to a list of AlgebraicValues
  • key(map_i) extracts the key of the ith entry of map
  • value(map_i) extracts the value of the ith entry of map

Types

All SATS types are BSATN-encoded by converting them to an AlgebraicValue, then BSATN-encoding that meta-value.

See the SATN JSON Format for more details of the conversion to meta values. Note that these meta values are converted to BSATN and not JSON.

Edit On Github