odra-codegen 0.7.1

Code generators for Odra IR.
Documentation
use derive_more::From;
use odra_ir::module::{Constructor, Method, ModuleImpl};
use proc_macro2::TokenStream;
use quote::{format_ident, quote, ToTokens, TokenStreamExt};
use syn::{punctuated::Punctuated, token::Comma};

use crate::GenerateCode;

pub(super) mod common;
mod deployer_casper_livenet;
mod deployer_casper_test;
mod deployer_mock_vm;

#[derive(From)]
pub struct Deploy<'a> {
    contract: &'a ModuleImpl
}

as_ref_for_contract_impl_generator!(Deploy);

impl GenerateCode for Deploy<'_> {
    fn generate_code(&self) -> TokenStream {
        let struct_ident = self.contract.ident();
        let ref_ident = format_ident!("{}Ref", struct_ident);
        let deployer_ident = format_ident!("{}Deployer", struct_ident);
        let deployer_comment = format!("Deployer for the [{}] contract.", struct_ident);

        let method_defs: Vec<&Method> = self.contract.get_public_method_iter().collect();
        let constructor_defs: Vec<&Constructor> = self.contract.get_constructor_iter().collect();

        let mock_vm_deployer_impl = deployer_mock_vm::generate_code(
            struct_ident,
            &deployer_ident,
            &ref_ident,
            &constructor_defs,
            &method_defs
        );
        let casper_test_deployer_impl = deployer_casper_test::generate_code(
            struct_ident,
            &deployer_ident,
            &ref_ident,
            &constructor_defs
        );
        let casper_livenet_deployer_impl = deployer_casper_livenet::generate_code(
            struct_ident,
            &deployer_ident,
            &ref_ident,
            &constructor_defs,
            &method_defs
        );

        quote! {
            #[doc = #deployer_comment]
            pub struct #deployer_ident;

            #[cfg(all(feature = "casper", not(target_arch = "wasm32")))]
            #casper_test_deployer_impl

            #[cfg(feature = "mock-vm")]
            #mock_vm_deployer_impl

            #[cfg(feature = "casper-livenet")]
            #casper_livenet_deployer_impl
        }
    }
}

fn args_to_fn_args<'a, T>(args: T) -> Punctuated<TokenStream, Comma>
where
    T: IntoIterator<Item = &'a syn::PatType>
{
    args.into_iter()
        .map(|arg| {
            let pat = &*arg.pat;
            match &*arg.ty {
                syn::Type::Reference(ty) => match &*ty.elem {
                    ty if matches!(ty, syn::Type::Array(_) | syn::Type::Slice(_)) => {
                        quote!(&odra::types::UncheckedGetter::get::<
                            odra::prelude::vec::Vec<_>
                        >(args, stringify!(#pat)))
                    }
                    _ => quote!(&odra::types::UncheckedGetter::get(args, stringify!(#pat)))
                },
                ty if matches!(ty, syn::Type::Array(_) | syn::Type::Slice(_)) => {
                    quote!(&odra::types::UncheckedGetter::get::<
                        odra::prelude::vec::Vec<_>
                    >(args, stringify!(#pat)))
                }
                _ => quote!(odra::types::UncheckedGetter::get(args, stringify!(#pat)))
            }
        })
        .collect::<Punctuated<TokenStream, Comma>>()
}

fn args_to_fn_cl_values<'a, T>(args: T) -> Punctuated<TokenStream, Comma>
where
    T: IntoIterator<Item = &'a syn::PatType>
{
    args.into_iter()
        .map(|arg| {
            let pat = &*arg.pat;
            match &*arg.ty {
                syn::Type::Reference(ty) => match &*ty.elem {
                    syn::Type::Array(inner_ty) => {
                        let inner_ty = &inner_ty.elem;
                        quote! {
                            &args.get(stringify!(#pat))
                                .cloned()
                                .unwrap()
                                .into_t::<odra::prelude::vec::Vec<#inner_ty>>()
                                .unwrap()
                                .as_slice()
                        }
                    }
                    syn::Type::Slice(inner_ty) => {
                        let inner_ty = &inner_ty.elem;
                        quote! {
                            &args.get(stringify!(#pat))
                                .cloned()
                                .unwrap()
                                .into_t::<odra::prelude::vec::Vec<#inner_ty>>()
                                .unwrap()
                                .as_slice()
                        }
                    }
                    ty => quote! {
                        &args.get(stringify!(#pat))
                            .cloned()
                            .unwrap()
                            .into_t::<#ty>()
                            .unwrap()
                    }
                },
                syn::Type::Array(inner_ty) => {
                    let inner_ty = &inner_ty.elem;
                    quote! {
                        args.get(stringify!(#pat))
                            .cloned()
                            .unwrap()
                            .into_t::<odra::prelude::vec::Vec<#inner_ty>>()
                            .unwrap()
                    }
                }
                syn::Type::Slice(inner_ty) => {
                    let inner_ty = &inner_ty.elem;
                    quote! {
                        args.get(stringify!(#pat))
                            .cloned()
                            .unwrap()
                            .into_t::<odra::prelude::vec::Vec<#inner_ty>>()
                            .unwrap()
                    }
                }
                ty => quote! {
                    args.get(stringify!(#pat))
                        .cloned()
                        .unwrap()
                        .into_t::<#ty>()
                        .unwrap()
                }
            }
        })
        .collect::<Punctuated<TokenStream, Comma>>()
}

fn args_to_runtime_args_stream<'a, T>(args: T) -> TokenStream
where
    T: IntoIterator<Item = &'a syn::PatType>
{
    let mut tokens = quote!(let mut args = odra::types::casper_types::RuntimeArgs::new(););
    tokens.append_all(args.into_iter().map(|arg| {
        let pat = &*arg.pat;
        quote! { let _ = args.insert(stringify!(#pat), #pat.clone()); }
    }));
    tokens.extend(quote!(args));
    tokens
}

fn args_to_arg_names_stream<'a, T>(args: T) -> TokenStream
where
    T: IntoIterator<Item = &'a syn::PatType>
{
    let args_stream = args
        .into_iter()
        .map(|arg| {
            let pat = &*arg.pat;
            let pat = pat.to_token_stream().to_string();
            quote!(args.push(odra::prelude::string::String::from(#pat));)
        })
        .collect::<TokenStream>();

    quote! {
        {
            let mut args: odra::prelude::vec::Vec<odra::prelude::string::String> = odra::prelude::vec![];
            #args_stream
            args
        }
    }
}