From f146dc7241f63ded1e35cf91326374fcef10068f Mon Sep 17 00:00:00 2001 From: driftluo Date: Wed, 3 Jul 2024 11:39:16 +0800 Subject: [PATCH] docs: add rust api doc --- docs/molecule_api.md | 85 +++++++++++++++++++ .../languages/rust/builder/implementation.rs | 9 ++ .../languages/rust/builder/setters.rs | 4 +- 3 files changed, 95 insertions(+), 3 deletions(-) create mode 100644 docs/molecule_api.md diff --git a/docs/molecule_api.md b/docs/molecule_api.md new file mode 100644 index 0000000..3f7aa35 --- /dev/null +++ b/docs/molecule_api.md @@ -0,0 +1,85 @@ +## 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 +```rust +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; + fn from_compatible_slice(slice: &[u8]) -> VerificationResult; + 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. + +```mol +vector Inner ; + +table Old { + a: Inner, + b: Inner, +} + +table New { + a: Inner, + b: Inner, + b: 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 +```rust +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::verify(slice, false).map(|_| Self::new_unchecked(slice)) + } + fn from_compatible_slice(slice: &'r [u8]) -> VerificationResult { + 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 + +```rust +pub trait Builder: Default { + type Entity: Entity; + const NAME: &'static str; + fn expected_length(&self) -> usize; + fn 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. diff --git a/tools/codegen/src/generator/languages/rust/builder/implementation.rs b/tools/codegen/src/generator/languages/rust/builder/implementation.rs index e396940..2dae763 100644 --- a/tools/codegen/src/generator/languages/rust/builder/implementation.rs +++ b/tools/codegen/src/generator/languages/rust/builder/implementation.rs @@ -290,6 +290,15 @@ fn gen_from_iter(name: &str, item_name: &str) -> m4::TokenStream { } } + impl From for #entity + where + T: ::core::iter::Iterator, + { + fn from(v: T) -> Self { + ::core::iter::FromIterator::from_iter(v.into_iter()) + } + } + #maybe_byte_vec ) } diff --git a/tools/codegen/src/generator/languages/rust/builder/setters.rs b/tools/codegen/src/generator/languages/rust/builder/setters.rs index 4d32e86..851a025 100644 --- a/tools/codegen/src/generator/languages/rust/builder/setters.rs +++ b/tools/codegen/src/generator/languages/rust/builder/setters.rs @@ -119,9 +119,7 @@ fn impl_setters_for_vector(inner_name: &str) -> m4::TokenStream { self } pub fn extend>(mut self, iter: T) -> Self { - for elem in iter { - self.0.push(elem); - } + self.0.extend(iter); self } pub fn replace(&mut self, index: usize, v: #inner) -> Option<#inner> {