Skip to content

Commit

Permalink
Generate odra::Module implementation (#268)
Browse files Browse the repository at this point in the history
* generate Module trait implementation
* generate odra::Module in examples
* update odra paths,
* update ModuleIR
  • Loading branch information
kpob authored Nov 28, 2023
1 parent 9aa7f1a commit 69b1520
Show file tree
Hide file tree
Showing 13 changed files with 462 additions and 115 deletions.
42 changes: 1 addition & 41 deletions examples2/src/counter_pack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use odra::Mapping;
use odra::Module;
use odra::ModuleWrapper;

#[odra_macros::module]
pub struct CounterPack {
env: Rc<ContractEnv>,
counter0: ModuleWrapper<Counter>,
Expand Down Expand Up @@ -61,47 +62,6 @@ impl CounterPack {
}
}

// autogenerated
mod odra_core_module {
use super::*;

impl Module for CounterPack {
fn new(env: Rc<ContractEnv>) -> Self {
let counter0 = ModuleWrapper::new(Rc::clone(&env), 0);
let counter1 = ModuleWrapper::new(Rc::clone(&env), 1);
let counter2 = ModuleWrapper::new(Rc::clone(&env), 2);
let counter3 = ModuleWrapper::new(Rc::clone(&env), 3);
let counter4 = ModuleWrapper::new(Rc::clone(&env), 4);
let counter5 = ModuleWrapper::new(Rc::clone(&env), 5);
let counter6 = ModuleWrapper::new(Rc::clone(&env), 6);
let counter7 = ModuleWrapper::new(Rc::clone(&env), 7);
let counter8 = ModuleWrapper::new(Rc::clone(&env), 8);
let counter9 = ModuleWrapper::new(Rc::clone(&env), 9);
let counters = Mapping::new(Rc::clone(&env), 10);
let counters_map = Mapping::new(Rc::clone(&env), 11);
Self {
env,
counter0,
counter1,
counter2,
counter3,
counter4,
counter5,
counter6,
counter7,
counter8,
counter9,
counters,
counters_map
}
}

fn env(&self) -> Rc<ContractEnv> {
self.env.clone()
}
}
}

#[cfg(odra_module = "CounterPack")]
#[cfg(target_arch = "wasm32")]
mod __counter_pack_wasm_parts {
Expand Down
23 changes: 1 addition & 22 deletions examples2/src/erc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ impl From<Erc20Error> for OdraError {
}
}

#[odra_macros::module]
pub struct Erc20 {
env: Rc<ContractEnv>,
total_supply: Variable<U256>,
Expand Down Expand Up @@ -138,28 +139,6 @@ impl Erc20 {
}
}

// autogenerated for general purpose module.
mod __erc20_module {
use super::Erc20;
use odra::{module::Module, prelude::*, ContractEnv, Mapping, Variable};

impl Module for Erc20 {
fn new(env: Rc<ContractEnv>) -> Self {
let total_supply = Variable::new(Rc::clone(&env), 1);
let balances = Mapping::new(Rc::clone(&env), 2);
Self {
env,
total_supply,
balances
}
}

fn env(&self) -> Rc<ContractEnv> {
self.env.clone()
}
}
}

#[cfg(odra_module = "Erc20")]
mod __erc20_schema {
use odra::{contract_def::ContractBlueprint2, prelude::String};
Expand Down
2 changes: 1 addition & 1 deletion odra-macros/src/ast/host_ref_item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,7 @@ mod ref_item_tests {
self.env.last_call().contract_last_call(self.address)
}

pub fn try_total_supply(&self) -> Result<U256, OdraError> {
pub fn try_total_supply(&self) -> Result<U256, odra::OdraError> {
self.env.call_contract(
self.address,
odra::CallDef::new(
Expand Down
2 changes: 2 additions & 0 deletions odra-macros/src/ast/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
mod deployer_item;
mod deployer_utils;
mod host_ref_item;
mod module_item;
mod parts_utils;
mod ref_item;
mod ref_utils;
mod test_parts;

pub(crate) use module_item::ModuleModItem;
pub(crate) use ref_item::RefItem;
pub(crate) use test_parts::{TestParts, TestPartsReexport};
192 changes: 192 additions & 0 deletions odra-macros/src/ast/module_item.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
use quote::{ToTokens, TokenStreamExt};
use syn::parse_quote;

use crate::{
ir::{EnumeratedTypedField, StructIR},
utils
};

use super::parts_utils::UseSuperItem;

#[derive(syn_derive::ToTokens)]
pub struct ModuleModItem {
mod_token: syn::token::Mod,
mod_ident: syn::Ident,
#[syn(braced)]
braces: syn::token::Brace,
#[syn(in = braces)]
use_super: UseSuperItem,
#[syn(in = braces)]
item: ModuleImplItem
}

impl TryFrom<&'_ StructIR> for ModuleModItem {
type Error = syn::Error;

fn try_from(ir: &'_ StructIR) -> Result<Self, Self::Error> {
Ok(Self {
mod_token: Default::default(),
mod_ident: ir.module_mod_ident(),
use_super: UseSuperItem,
braces: Default::default(),
item: ir.try_into()?
})
}
}

#[derive(syn_derive::ToTokens)]
struct ModuleImplItem {
impl_token: syn::token::Impl,
trait_path: syn::Type,
for_token: syn::token::For,
module_path: syn::Ident,
#[syn(braced)]
braces: syn::token::Brace,
#[syn(in = braces)]
new_fn: NewModuleFnItem,
#[syn(in = braces)]
env_fn: EnvFnItem
}

impl TryFrom<&'_ StructIR> for ModuleImplItem {
type Error = syn::Error;

fn try_from(ir: &'_ StructIR) -> Result<Self, Self::Error> {
Ok(Self {
impl_token: Default::default(),
trait_path: utils::ty::module(),
for_token: Default::default(),
module_path: ir.module_ident(),
braces: Default::default(),
new_fn: ir.try_into()?,
env_fn: EnvFnItem
})
}
}

#[derive(syn_derive::ToTokens)]
struct NewModuleFnItem {
sig: syn::Signature,
#[syn(braced)]
braces: syn::token::Brace,
#[syn(in = braces)]
#[to_tokens(|tokens, val| tokens.append_all(val))]
fields: Vec<ModuleFieldItem>,
#[syn(in = braces)]
instance: ModuleInstanceItem
}

impl TryFrom<&'_ StructIR> for NewModuleFnItem {
type Error = syn::Error;

fn try_from(ir: &'_ StructIR) -> Result<Self, Self::Error> {
let ty_contract_env = utils::ty::contract_env();
let env = utils::ident::env();
let fields = ir.typed_fields()?;
Ok(Self {
sig: parse_quote!(fn new(#env: Rc<#ty_contract_env>) -> Self),
braces: Default::default(),
fields: fields.iter().map(Into::into).collect(),
instance: ir.try_into()?
})
}
}

#[derive(syn_derive::ToTokens)]
struct ModuleFieldItem {
let_token: syn::token::Let,
ident: syn::Ident,
assign_token: syn::token::Eq,
field_expr: syn::Expr,
semi_token: syn::token::Semi
}

impl From<&'_ EnumeratedTypedField> for ModuleFieldItem {
fn from(field: &'_ EnumeratedTypedField) -> Self {
Self {
let_token: Default::default(),
ident: field.ident.clone(),
assign_token: Default::default(),
field_expr: utils::expr::new_type(&field.ty, &utils::ident::env(), field.idx),
semi_token: Default::default()
}
}
}

#[derive(syn_derive::ToTokens)]
struct ModuleInstanceItem {
self_token: syn::token::SelfType,
#[syn(braced)]
braces: syn::token::Brace,
#[syn(in = braces)]
values: syn::punctuated::Punctuated<syn::Ident, syn::Token![,]>
}

impl TryFrom<&'_ StructIR> for ModuleInstanceItem {
type Error = syn::Error;

fn try_from(ir: &'_ StructIR) -> Result<Self, Self::Error> {
Ok(Self {
self_token: Default::default(),
braces: Default::default(),
values: ir.field_names()?.into_iter().collect()
})
}
}

struct EnvFnItem;

impl ToTokens for EnvFnItem {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
let ty_contract_env = utils::ty::contract_env();
let m_env = utils::member::env();

tokens.extend(quote::quote!(
fn env(&self) -> Rc<#ty_contract_env> {
#m_env.clone()
}
))
}
}

#[cfg(test)]
mod test {
use crate::test_utils;
use quote::quote;

use super::ModuleModItem;

#[test]
fn counter_pack() {
let module = test_utils::mock_module_definition();
let expected = quote!(
mod __counter_pack_module {
use super::*;

impl odra::Module for CounterPack {
fn new(env: Rc<odra::ContractEnv>) -> Self {
let counter0 = ModuleWrapper::new(Rc::clone(&env), 0u8);
let counter1 = ModuleWrapper::new(Rc::clone(&env), 1u8);
let counter2 = ModuleWrapper::new(Rc::clone(&env), 2u8);
let counters = Variable::new(Rc::clone(&env), 3u8);
let counters_map = Mapping::new(Rc::clone(&env), 4u8);
Self {
env,
counter0,
counter1,
counter2,
counters,
counters_map
}
}

fn env(&self) -> Rc<odra::ContractEnv> {
self.env.clone()
}
}
}
);
let actual = ModuleModItem::try_from(&module).unwrap();
test_utils::assert_eq(actual, expected);
}
}
2 changes: 1 addition & 1 deletion odra-macros/src/ast/test_parts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ mod test {
self.env.last_call().contract_last_call(self.address)
}

pub fn try_total_supply(&self) -> Result<U256, OdraError> {
pub fn try_total_supply(&self) -> Result<U256, odra::OdraError> {
self.env.call_contract(
self.address,
odra::CallDef::new(
Expand Down
Loading

0 comments on commit 69b1520

Please sign in to comment.