Skip to content

Latest commit

 

History

History
85 lines (66 loc) · 3.32 KB

molecule_api.md

File metadata and controls

85 lines (66 loc) · 3.32 KB

Molecule API

Molecule is based on schema serialization. The serialization format generated by any language based on the same schema should be consistent. The most basic API for multiple languages ​​should include data verification, schema compatibility reading, serialization and deserialization, and obtaining raw data (excluding the molecule header).

Rust API

In the basic implementation of rust, the generated code uses three traits to implement three different functions of a structure:

Entity

pub trait Entity: fmt::Debug + Default + Clone {
    type Builder: Builder;
    const NAME: &'static str;
    fn new_unchecked(data: Bytes) -> Self;
    fn as_bytes(&self) -> Bytes;
    fn as_slice(&self) -> &[u8];
    fn from_slice(slice: &[u8]) -> VerificationResult<Self>;
    fn from_compatible_slice(slice: &[u8]) -> VerificationResult<Self>;
    fn new_builder() -> Self::Builder;
    fn as_builder(self) -> Self::Builder;
}

Entity corresponds to a serialized data structure. There are two APIs that are easily confused: as_slice defined in the trait and raw_data that comes with its own structure.

as_slice: Complete molecule format data raw_data: Original data, i.e. without the molecule header

Molecule supports compatible reading of data. The so-called compatibility refers to a structure like table, which can dynamically add fields. The old schema can read the data generated by the schema after adding fields, but it does not support deleting fields.

vector Inner <byte>;

table Old {
    a: Inner,
    b: Inner,
}

table New {
    a: Inner,
    b: Inner,
    c: Inner,
}

Like the scheme in the example above, Old can use the from_compatible_slice api to read New's data.At the same time, the structure will have APIs such as count_extra_fields/has_extra_fields/has_extra_fields to let users know that there is extra data in the read data. It is currently compatible with reading.

Reader

pub trait Reader<'r>: Sized + fmt::Debug + Clone + Copy {
    type Entity: Entity;
    const NAME: &'static str;
    fn verify(slice: &[u8], compatible: bool) -> VerificationResult<()>;
    fn new_unchecked(slice: &'r [u8]) -> Self;
    fn as_slice(&self) -> &'r [u8];
    fn from_slice(slice: &'r [u8]) -> VerificationResult<Self> {
        Self::verify(slice, false).map(|_| Self::new_unchecked(slice))
    }
    fn from_compatible_slice(slice: &'r [u8]) -> VerificationResult<Self> {
        Self::verify(slice, true).map(|_| Self::new_unchecked(slice))
    }
    fn to_entity(&self) -> Self::Entity;
}

Each structure will generate at least one corresponding Reader structure, which has the ability to obtain the field data inside the structure.

Builder

pub trait Builder: Default {
    type Entity: Entity;
    const NAME: &'static str;
    fn expected_length(&self) -> usize;
    fn write<W: io::Write>(&self, writer: &mut W) -> io::Result<()>;
    fn build(&self) -> Self::Entity;
}

Builder is the key to building and serializing the molecule structure. Use the builder mode to generate a builder structure, put all fields into it, and convert it into a serialized structure(Entity) through the build API.

Union

The union structure will have two more structures than other structures when generating code, corresponding to different internal data types, and ends with Union.