Skip to content

Commit

Permalink
attempt to add primitive types
Browse files Browse the repository at this point in the history
Signed-off-by: Eval EXEC <execvy@gmail.com>
  • Loading branch information
eval-exec committed Jan 11, 2023
1 parent 5f94aa8 commit 6c4c247
Show file tree
Hide file tree
Showing 14 changed files with 359 additions and 16 deletions.
2 changes: 1 addition & 1 deletion bindings/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 2 additions & 0 deletions std/rust/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
target/
Cargo.lock
12 changes: 12 additions & 0 deletions std/rust/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "molecule-std"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
molecule = { path = "../../bindings/rust" }

[build-dependencies]
codegen = { package ="molecule-codegen", path = "../../tools/codegen" }
20 changes: 20 additions & 0 deletions std/rust/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
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()
.expand_primitive_types()
.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);
}
14 changes: 14 additions & 0 deletions std/rust/primitive_types.mol
Original file line number Diff line number Diff line change
@@ -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];
15 changes: 15 additions & 0 deletions std/rust/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
pub mod prelude;
pub mod primitive_types;

extern crate alloc;

pub use alloc::{borrow::ToOwned, vec, vec::Vec};
pub use molecule::{
bytes,
bytes::Bytes,
error,
error::VerificationResult,
hex_string, io,
primitive::{Byte, ByteReader},
verification_error,
};
165 changes: 165 additions & 0 deletions std/rust/src/prelude.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
include!(concat!(env!("OUT_DIR"), "/primitive_types.rs"));

pub use molecule::{bytes::Bytes, prelude::*, verification_error};

pub trait Unpack<T> {
/// Unpack binary data into rust types.
fn unpack(&self) -> T;
}

/// A syntactic sugar to convert a rust type into binary data.
pub trait Pack<T: Entity> {
/// 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<Uint64> for u64 {
fn pack(&self) -> Uint64 {
Uint64::new_unchecked(Bytes::from(self.to_le_bytes().to_vec()))
}
}

impl<'r> Unpack<u64> 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<Uint32> for u32 {
fn pack(&self) -> Uint32 {
Uint32::new_unchecked(Bytes::from(self.to_le_bytes().to_vec()))
}
}

impl<'r> Unpack<u32> 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<Uint16> for u16 {
fn pack(&self) -> Uint16 {
Uint16::new_unchecked(Bytes::from(self.to_le_bytes().to_vec()))
}
}

impl<'r> Unpack<u16> 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<Uint8> for u8 {
fn pack(&self) -> Uint8 {
Uint8::new_unchecked(Bytes::from(self.to_le_bytes().to_vec()))
}
}

impl<'r> Unpack<u8> 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<Int64> for i64 {
fn pack(&self) -> Int64 {
Int64::new_unchecked(Bytes::from(self.to_le_bytes().to_vec()))
}
}

impl<'r> Unpack<i64> 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<Int32> for i32 {
fn pack(&self) -> Int32 {
Int32::new_unchecked(Bytes::from(self.to_le_bytes().to_vec()))
}
}

impl<'r> Unpack<i32> 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<Int16> for i16 {
fn pack(&self) -> Int16 {
Int16::new_unchecked(Bytes::from(self.to_le_bytes().to_vec()))
}
}

impl<'r> Unpack<i16> 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<Int8> for i8 {
fn pack(&self) -> Int8 {
Int8::new_unchecked(Bytes::from(self.to_le_bytes().to_vec()))
}
}

impl<'r> Unpack<i8> 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<Bool> for bool {
fn pack(&self) -> Bool {
let b = u8::from(*self);
Bool::new_unchecked(Bytes::from(vec![b]))
}
}

impl<'r> Unpack<bool> for BoolReader<'r> {
fn unpack(&self) -> bool {
match self.as_slice()[0] {
0 => false,
1 => true,
_ => unreachable!(),
}
}
}
impl_conversion_for_entity_unpack!(bool, Bool);
1 change: 1 addition & 0 deletions std/rust/src/primitive_types.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include!(concat!(env!("OUT_DIR"), "/primitive_types.rs"));
25 changes: 21 additions & 4 deletions tools/codegen/src/ast/verified/complete.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::ast::verified::{PRIMITIVE_BYTE, PRIMITIVE_EXT_TYPES};
use std::{
collections::{HashMap, HashSet},
rc::Rc,
Expand Down Expand Up @@ -162,23 +163,39 @@ impl CompleteRawDecl for raw::TableDecl {
}

impl super::Ast {
pub(crate) fn complete(raw: raw::Ast) -> Self {
pub(crate) fn complete(raw: raw::Ast, expand_primitive_ext_types: bool) -> Self {
let mut decls_idx = HashMap::new();
let mut decls_keys = HashSet::new();
for decl in raw.decls() {
let name = decl.name();
if super::TopDecl::new_primitive(name.to_lowercase().as_str()).is_some() {
if expand_primitive_ext_types {
if super::TopDecl::new_primitive_without_ext(name.to_lowercase().as_str()).is_some()
{
panic!("the name `{}` is reserved", name);
}
} else if super::TopDecl::new_primitive(name.to_lowercase().as_str()).is_some() {
panic!("the name `{}` is reserved", name);
}
if decls_idx.insert(name, decl).is_some() || !decls_keys.insert(name) {
panic!("the name `{}` is used more than once", name);
};
}
let mut decls_result = HashMap::new();

decls_result.insert(
"byte",
Rc::new(super::TopDecl::new_primitive("byte").unwrap()),
PRIMITIVE_BYTE,
Rc::new(super::TopDecl::new_primitive(PRIMITIVE_BYTE).unwrap()),
);

if !expand_primitive_ext_types {
PRIMITIVE_EXT_TYPES.iter().for_each(|&primitive_type| {
decls_result.insert(
primitive_type,
Rc::new(super::TopDecl::new_primitive(primitive_type).unwrap()),
);
});
}

loop {
if decls_keys.is_empty() {
break;
Expand Down
72 changes: 71 additions & 1 deletion tools/codegen/src/ast/verified/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,29 @@ mod recover;
pub use default_content::DefaultContent;
pub use has_name::HasName;

const PRIMITIVE_BYTE: &str = "byte";

const PRIMITIVE_UINT64: &str = "uint64";
const PRIMITIVE_UINT32: &str = "uint32";
const PRIMITIVE_UINT16: &str = "uint16";
const PRIMITIVE_UINT8: &str = "uint8";
const PRIMITIVE_INT64: &str = "int64";
const PRIMITIVE_INT32: &str = "int32";
const PRIMITIVE_INT16: &str = "int16";
const PRIMITIVE_INT8: &str = "int8";
const PRIMITIVE_BOOL: &str = "bool";
const PRIMITIVE_EXT_TYPES: &[&str] = &[
PRIMITIVE_UINT64,
PRIMITIVE_UINT32,
PRIMITIVE_UINT16,
PRIMITIVE_UINT8,
PRIMITIVE_INT64,
PRIMITIVE_INT32,
PRIMITIVE_INT16,
PRIMITIVE_INT8,
PRIMITIVE_BOOL,
];

type Deps<'a> = HashMap<&'a str, Rc<super::TopDecl>>;

#[derive(Debug, Property)]
Expand Down Expand Up @@ -135,7 +158,54 @@ impl Ast {
impl TopDecl {
fn new_primitive(name: &str) -> Option<Self> {
match name {
"byte" => Some(Primitive {
PRIMITIVE_BYTE => Some(Primitive {
name: name.to_owned(),
size: 1,
}),
PRIMITIVE_UINT64 => Some(Primitive {
name: name.to_owned(),
size: 8,
}),
PRIMITIVE_UINT32 => Some(Primitive {
name: name.to_owned(),
size: 4,
}),
PRIMITIVE_UINT16 => Some(Primitive {
name: name.to_owned(),
size: 2,
}),
PRIMITIVE_UINT8 => Some(Primitive {
name: name.to_owned(),
size: 1,
}),
PRIMITIVE_INT64 => Some(Primitive {
name: name.to_owned(),
size: 8,
}),
PRIMITIVE_INT32 => Some(Primitive {
name: name.to_owned(),
size: 4,
}),
PRIMITIVE_INT16 => Some(Primitive {
name: name.to_owned(),
size: 2,
}),
PRIMITIVE_INT8 => Some(Primitive {
name: name.to_owned(),
size: 1,
}),
PRIMITIVE_BOOL => Some(Primitive {
name: name.to_owned(),
size: 1,
}),
_ => None,
}
.map(Self::Primitive)
}

fn new_primitive_without_ext(name: &str) -> Option<Self> {
match name {
PRIMITIVE_BYTE => Some(Primitive {
name: name.to_owned(),
size: 1,
}),
Expand Down
Loading

0 comments on commit 6c4c247

Please sign in to comment.