1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#![recursion_limit = "128"]
extern crate proc_macro;
use proc_macro::TokenStream;
use std::env;

use quote::quote;
use syn::Item;

mod contract;
mod subcontract;
mod util;

/// Generates a companion Trait which has a default type `Impl`, which implements this trait.
///
#[proc_macro_attribute]
pub fn subcontract(_: TokenStream, item: TokenStream) -> TokenStream {
    let parsed: Item = syn::parse(item).unwrap();
    subcontract::generate(parsed).into()
}

#[proc_macro_derive(IntoKey)]
pub fn into_key(item: TokenStream) -> TokenStream {
    syn::parse::<Item>(item)
        .and_then(subcontract::into_key::from_item)
        .map_or_else(|e| e.to_compile_error().into(), Into::into)
}

#[proc_macro_derive(Lazy)]
pub fn lazy(item: TokenStream) -> TokenStream {
    syn::parse::<Item>(item)
        .and_then(subcontract::lazy::from_item)
        .map_or_else(|e| e.to_compile_error().into(), Into::into)
}

/// Generates the soroban contract code combining all Subcontracts
#[proc_macro]
pub fn soroban_contract(_: TokenStream) -> TokenStream {
    let cargo_file = manifest();
    let subcontract = loam_build::deps::subcontract(&cargo_file).unwrap();

    let deps = subcontract
        .iter()
        .map(|i| i.0.to_path_buf().into_std_path_buf())
        .collect::<Vec<_>>();

    contract::generate(&deps).into()
}

fn manifest() -> std::path::PathBuf {
    std::path::PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()).join("Cargo.toml")
}

/// Generates a contract Client for a given contract.
/// It is expected that the name should be the same as the published contract or a contract in your current workspace.
#[proc_macro]
pub fn import_contract(tokens: TokenStream) -> TokenStream {
    let cargo_file = manifest();
    let mut dir = loam_build::get_target_dir(&cargo_file)
        .unwrap()
        .join(tokens.to_string());
    let name = syn::parse::<syn::Ident>(tokens).expect("The input must be a valid identifier");
    dir.set_extension("wasm");
    let binding = dir.canonicalize().unwrap();
    let file = binding.to_str().unwrap();
    quote! {
        mod #name {
            use loam_sdk::soroban_sdk;
            loam_sdk::soroban_sdk::contractimport!(file = #file);
        }
    }
    .into()
}