4 releases

0.0.4 Oct 11, 2024
0.0.3 Oct 11, 2024
0.0.2 Sep 19, 2024
0.0.1 Sep 19, 2024

#1 in #inter-chain

Download history 228/week @ 2024-09-14 73/week @ 2024-09-21 24/week @ 2024-09-28 218/week @ 2024-10-05 182/week @ 2024-10-12 14/week @ 2024-10-19 5/week @ 2024-10-26 5/week @ 2024-11-02

422 downloads per month
Used in 4 crates

Apache-2.0

150KB
3K SLoC

WARNING: This is an API preview! Expect major bugs, glaring omissions, and breaking changes!

This crate defines the encoding traits and schemas for the Interchain SDK which can be used in message parameter and return types, serializable structs and enums, and objects in storage.

Basic Types

The basic types supported intrinsically are:

Custom types may be derived using the SchemaValue derive macro. As a general rule, if a type implements SchemaValue it can be used as a function or struct parameter.

Supported Encodings

Similar to the Serde framework, ixc_schema types can support multiple encodings through different implementations of the encoder::Encoder and decoder::Decoder traits. Unlike Serde, these traits are object safe and dynamic dispatch is used wherever possible so that code size does not expand due to Rust's mono-morphization of generics

Currently only a simple native binary encoding is supported but protobuf, JSON, and encodings to other popular VM formats are planned in the future.

Memory Management

If you read the list of supported types carefully, you may notice that borrowed strings and slices are both supported. This means that we can define types with lifetimes and deserialize borrowed data, just like in the popular Serde framework. Ex:

pub struct Coin<'a> {
  pub denom: &'a str,
  pub amount: u128,  
}

We improve upon Serde's approach with a memory management system to properly deal with cases where we simply cannot borrow directly from the input data. In Serde, if we deserialize the above Coin structure from JSON input, it wil work some of the time but will fail with an error whenever the input data contains JSON escape characters (ex. "foo\tbar"). This is because a borrowed data structure must have some owner, but in Serde the only possible owner is the input itself.

In ixc_schema we use a bump allocator under the hood to hold onto any intermediate allocation that must take place to be able to borrow not just strings, but slices of any sort of data. When data is decoded there is a "memory manager" that holds onto the original input data and any temporary allocations and then deallocates them in mass when we're done with the data. Because decoding is a phase-oriented operation, this model works well and is very efficient. Because of this property, ixc_schema can support complex data structures and manage memory correctly, without needing to interact with the general purpose Rust global allocator. With this model, in the future it will likely be possible to build crates targeting virtual machines such as WebAssembly in no_std mode without any sort of global allocator.

To make the best use of the built-in bump allocator, it is recommended to avoid uses of String and Vec<T> in favor of &str and &[T] respectively. You can also use Cow<str> and Cow<[T]> to have the optionality to use borrowed or owned data.

Dependencies

~4MB
~71K SLoC