From a58bf91a271b76567ef865a66772f7cea5a9f074 Mon Sep 17 00:00:00 2001 From: Eval EXEC Date: Thu, 12 Jan 2023 11:54:15 +0800 Subject: [PATCH] attempt to add primitive types Signed-off-by: Eval EXEC --- bindings/rust/src/lib.rs | 2 +- std/primitive_types.mol | 14 ++ std/rust/.gitignore | 2 + std/rust/Cargo.toml | 28 +++ std/rust/build.rs | 19 ++ std/rust/src/lib.rs | 24 +++ std/rust/src/pack.rs | 164 ++++++++++++++++++ tools/codegen/Cargo.toml | 1 + tools/codegen/src/ast/raw/mod.rs | 4 +- tools/codegen/src/ast/verified/mod.rs | 34 +++- .../src/generator/languages/rust/mod.rs | 4 + 11 files changed, 292 insertions(+), 4 deletions(-) create mode 100644 std/primitive_types.mol create mode 100644 std/rust/.gitignore create mode 100644 std/rust/Cargo.toml create mode 100644 std/rust/build.rs create mode 100644 std/rust/src/lib.rs create mode 100644 std/rust/src/pack.rs diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 528c57b..a7084d3 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -21,7 +21,7 @@ cfg_if::cfg_if! { pub mod error; pub mod prelude; -mod primitive; +pub mod primitive; // Little Endian pub type Number = u32; diff --git a/std/primitive_types.mol b/std/primitive_types.mol new file mode 100644 index 0000000..6290143 --- /dev/null +++ b/std/primitive_types.mol @@ -0,0 +1,14 @@ +// Unsigned integers +array uint64 [byte; 8]; +array uint32 [byte; 4]; +array uint16 [byte; 2]; +array uint8 [byte; 1]; + +// Signed integers +array int64 [byte; 8]; +array int32 [byte; 4]; +array int16 [byte; 2]; +array int8 [byte; 1]; + +// Bool +array bool [byte; 1]; \ No newline at end of file diff --git a/std/rust/.gitignore b/std/rust/.gitignore new file mode 100644 index 0000000..4470988 --- /dev/null +++ b/std/rust/.gitignore @@ -0,0 +1,2 @@ +target/ +Cargo.lock \ No newline at end of file diff --git a/std/rust/Cargo.toml b/std/rust/Cargo.toml new file mode 100644 index 0000000..c12eff4 --- /dev/null +++ b/std/rust/Cargo.toml @@ -0,0 +1,28 @@ +[package] +name = "molecule-std" +version = "0.0.1" +authors = ["Nervos Core Dev "] +edition = "2018" +description = "std primitive types for molecule." +homepage = "https://github.com/nervosnetwork/molecule" +repository = "https://github.com/nervosnetwork/molecule" +keywords = ["molecule", "code-generation", "serialization"] +categories = [ + "parser-implementations", + "development-tools::build-utils", + "encoding", + "data-structures" +] +license = "MIT" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +molecule = { path = "../../bindings/rust" } + +[features] +default = [] +with-primitive-types = [] + +[build-dependencies] +codegen = { package ="molecule-codegen", path = "../../tools/codegen" , features = ["gen-primitive-types"]} \ No newline at end of file diff --git a/std/rust/build.rs b/std/rust/build.rs new file mode 100644 index 0000000..de258bd --- /dev/null +++ b/std/rust/build.rs @@ -0,0 +1,19 @@ +use codegen::{Compiler, Language}; + +fn compile_schema(schema: &str) { + let mut compiler = Compiler::new(); + compiler + .input_schema_file(schema) + .generate_code(Language::Rust) + .output_dir_set_default() + .run() + .unwrap(); + println!("cargo:rerun-if-changed={}", schema); +} + +fn main() { + println!("cargo:rerun-if-changed=../primitive_types.mol"); + compile_schema("../primitive_types.mol"); + let out_dir = ::std::env::var("OUT_DIR").unwrap(); + println!("{}", out_dir); +} diff --git a/std/rust/src/lib.rs b/std/rust/src/lib.rs new file mode 100644 index 0000000..947b631 --- /dev/null +++ b/std/rust/src/lib.rs @@ -0,0 +1,24 @@ +pub mod pack; + +pub mod io { + pub use molecule::io::{self, *}; +} +pub mod error { + pub use molecule::error::{self, *}; +} + +pub mod bytes { + pub use molecule::bytes::{self, *}; +} + +pub mod prelude { + pub use molecule::prelude::*; +} + +pub mod primitive { + pub use molecule::primitive::{self, *}; +} + +pub mod primitives { + include!(concat!(env!("OUT_DIR"), "/primitive_types.rs")); +} diff --git a/std/rust/src/pack.rs b/std/rust/src/pack.rs new file mode 100644 index 0000000..189a323 --- /dev/null +++ b/std/rust/src/pack.rs @@ -0,0 +1,164 @@ +use crate::prelude::*; +use crate::primitives::*; + +pub trait Unpack { + /// Unpack binary data into rust types. + fn unpack(&self) -> T; +} + +/// A syntactic sugar to convert a rust type into binary data. +pub trait Pack { + /// Packs a rust type into binary data. + fn pack(&self) -> T; +} + +macro_rules! impl_conversion_for_entity_unpack { + ($original:ty, $entity:ident) => { + impl Unpack<$original> for $entity { + fn unpack(&self) -> $original { + self.as_reader().unpack() + } + } + }; +} + +impl Pack for u64 { + fn pack(&self) -> Uint64 { + Uint64::new_unchecked(Bytes::from(self.to_le_bytes().to_vec())) + } +} + +impl<'r> Unpack for Uint64Reader<'r> { + fn unpack(&self) -> u64 { + let mut b = [0u8; 8]; + b.copy_from_slice(self.as_slice()); + u64::from_le_bytes(b) + } +} +impl_conversion_for_entity_unpack!(u64, Uint64); + +impl Pack for u32 { + fn pack(&self) -> Uint32 { + Uint32::new_unchecked(Bytes::from(self.to_le_bytes().to_vec())) + } +} + +impl<'r> Unpack for Uint32Reader<'r> { + fn unpack(&self) -> u32 { + let mut b = [0u8; 4]; + b.copy_from_slice(self.as_slice()); + u32::from_le_bytes(b) + } +} +impl_conversion_for_entity_unpack!(u32, Uint32); + +impl Pack for u16 { + fn pack(&self) -> Uint16 { + Uint16::new_unchecked(Bytes::from(self.to_le_bytes().to_vec())) + } +} + +impl<'r> Unpack for Uint16Reader<'r> { + fn unpack(&self) -> u16 { + let mut b = [0u8; 2]; + b.copy_from_slice(self.as_slice()); + u16::from_le_bytes(b) + } +} +impl_conversion_for_entity_unpack!(u16, Uint16); + +impl Pack for u8 { + fn pack(&self) -> Uint8 { + Uint8::new_unchecked(Bytes::from(self.to_le_bytes().to_vec())) + } +} + +impl<'r> Unpack for Uint8Reader<'r> { + fn unpack(&self) -> u8 { + let mut b = [0u8; 1]; + b.copy_from_slice(self.as_slice()); + u8::from_le_bytes(b) + } +} +impl_conversion_for_entity_unpack!(u8, Uint8); + +// Signed integers + +impl Pack for i64 { + fn pack(&self) -> Int64 { + Int64::new_unchecked(Bytes::from(self.to_le_bytes().to_vec())) + } +} + +impl<'r> Unpack for Int64Reader<'r> { + fn unpack(&self) -> i64 { + let mut b = [0u8; 8]; + b.copy_from_slice(self.as_slice()); + i64::from_le_bytes(b) + } +} +impl_conversion_for_entity_unpack!(i64, Int64); + +impl Pack for i32 { + fn pack(&self) -> Int32 { + Int32::new_unchecked(Bytes::from(self.to_le_bytes().to_vec())) + } +} + +impl<'r> Unpack for Int32Reader<'r> { + fn unpack(&self) -> i32 { + let mut b = [0u8; 4]; + b.copy_from_slice(self.as_slice()); + i32::from_le_bytes(b) + } +} +impl_conversion_for_entity_unpack!(i32, Int32); + +impl Pack for i16 { + fn pack(&self) -> Int16 { + Int16::new_unchecked(Bytes::from(self.to_le_bytes().to_vec())) + } +} + +impl<'r> Unpack for Int16Reader<'r> { + fn unpack(&self) -> i16 { + let mut b = [0u8; 2]; + b.copy_from_slice(self.as_slice()); + i16::from_le_bytes(b) + } +} +impl_conversion_for_entity_unpack!(i16, Int16); + +impl Pack for i8 { + fn pack(&self) -> Int8 { + Int8::new_unchecked(Bytes::from(self.to_le_bytes().to_vec())) + } +} + +impl<'r> Unpack for Int8Reader<'r> { + fn unpack(&self) -> i8 { + let mut b = [0u8; 1]; + b.copy_from_slice(self.as_slice()); + i8::from_le_bytes(b) + } +} +impl_conversion_for_entity_unpack!(i8, Int8); + +// Bool +impl Pack for bool { + fn pack(&self) -> Bool { + let b = u8::from(*self); + Bool::new_unchecked(Bytes::from(vec![b])) + } +} + +impl<'r> Unpack for BoolReader<'r> { + fn unpack(&self) -> bool { + match self.as_slice()[0] { + 0 => false, + 1 => true, + _ => unreachable!(), + } + } +} +impl_conversion_for_entity_unpack!(bool, Bool); diff --git a/tools/codegen/Cargo.toml b/tools/codegen/Cargo.toml index 4c1202c..6806e33 100644 --- a/tools/codegen/Cargo.toml +++ b/tools/codegen/Cargo.toml @@ -32,6 +32,7 @@ serde_yaml = { version = "0.8.15", optional = true } [features] default = [] compiler-plugin = ["serde", "serde_json", "serde_yaml"] +gen-primitive-types = [] [badges] maintenance = { status = "experimental" } diff --git a/tools/codegen/src/ast/raw/mod.rs b/tools/codegen/src/ast/raw/mod.rs index 6b97274..6765ced 100644 --- a/tools/codegen/src/ast/raw/mod.rs +++ b/tools/codegen/src/ast/raw/mod.rs @@ -44,7 +44,7 @@ pub(crate) struct UnionDecl { imported_depth: usize, } -#[derive(Debug, Property)] +#[derive(Debug, Property, Clone)] pub(crate) struct ArrayDecl { name: String, item: ItemDecl, @@ -73,7 +73,7 @@ pub(crate) struct TableDecl { imported_depth: usize, } -#[derive(Debug, Property)] +#[derive(Debug, Property, Clone)] pub(crate) struct ItemDecl { typ: String, } diff --git a/tools/codegen/src/ast/verified/mod.rs b/tools/codegen/src/ast/verified/mod.rs index 3f49e40..ec8cab8 100644 --- a/tools/codegen/src/ast/verified/mod.rs +++ b/tools/codegen/src/ast/verified/mod.rs @@ -14,6 +14,25 @@ pub use has_name::HasName; type Deps<'a> = HashMap<&'a str, Rc>; +#[cfg(feature = "gen-primitive-types")] +use std::path::PathBuf; + +#[cfg(feature = "gen-primitive-types")] +fn primitive_types( + path: &PathBuf, +) -> Result, pest::error::Error> { + use crate::utils::PairsUtils; + crate::parser::Parser::preprocess(path).map(|ast| { + ast.decls() + .iter() + .map(|decl| match decl { + crate::ast::raw::TopDecl::Array(array) => array.clone(), + _ => panic!("primitive types is not array"), + }) + .collect::>() + }) +} + #[derive(Debug, Property)] #[property(get(public))] pub struct Ast { @@ -139,7 +158,20 @@ impl TopDecl { name: name.to_owned(), size: 1, }), - _ => None, + _ => { + #[cfg(not(feature = "gen-primitive-types"))] + return None; + + #[cfg(feature = "gen-primitive-types")] + primitive_types(&PathBuf::from("../../../../../std/primitive_types.mol")) + .unwrap() + .iter() + .find(|primitive_decl| x.name().eq(name)) + .map(|primitive_decl| Primitive { + name: primitive_decl.name().to_string(), + size: primitive_decl.item_count(), + }) + } } .map(Self::Primitive) } diff --git a/tools/codegen/src/generator/languages/rust/mod.rs b/tools/codegen/src/generator/languages/rust/mod.rs index 86bebb3..755139e 100644 --- a/tools/codegen/src/generator/languages/rust/mod.rs +++ b/tools/codegen/src/generator/languages/rust/mod.rs @@ -41,7 +41,11 @@ impl super::LanguageGenerator for Generator { writeln!(writer, "// Generated by Molecule {}", VERSION)?; writeln!(writer)?; let code = quote!( + use molecule_std as molecule; + use molecule::prelude::*; + #[cfg(feature = "with-primitive-types")] + use molecule::primitives::*; ); write!(writer, "{}", code)?; let imports = ast.imports();