loam_sdk_macro/
lib.rs

1#![recursion_limit = "128"]
2extern crate proc_macro;
3use proc_macro::TokenStream;
4use std::env;
5use subcontract::derive_contract_impl;
6use subcontract::storage;
7
8use quote::quote;
9use syn::Item;
10
11mod contract;
12mod subcontract;
13mod util;
14
15/// Generates a companion Trait which has a default type `Impl`, which implements this trait.
16///
17/// # Panics
18///
19/// This macro will panic if:
20/// - The input `TokenStream` cannot be parsed into a valid Rust item.
21/// - The `subcontract::generate` function fails to generate the companion trait.
22///
23#[proc_macro_attribute]
24pub fn subcontract(_: TokenStream, item: TokenStream) -> TokenStream {
25    let parsed: Item = syn::parse(item).unwrap();
26    subcontract::generate(&parsed).into()
27}
28
29#[deprecated(since = "0.9.0", note = "Please use #[loamstorage] instead.")]
30#[proc_macro_derive(IntoKey)]
31pub fn into_key(item: TokenStream) -> TokenStream {
32    syn::parse::<Item>(item)
33        .and_then(subcontract::into_key::from_item)
34        .map_or_else(|e| e.to_compile_error().into(), Into::into)
35}
36
37#[proc_macro_derive(Lazy)]
38pub fn lazy(item: TokenStream) -> TokenStream {
39    syn::parse::<Item>(item)
40        .and_then(subcontract::lazy::from_item)
41        .map_or_else(|e| e.to_compile_error().into(), Into::into)
42}
43
44pub(crate) fn manifest() -> std::path::PathBuf {
45    std::path::PathBuf::from(
46        env::var("CARGO_MANIFEST_DIR").expect("failed to finde cargo manifest"),
47    )
48    .join("Cargo.toml")
49}
50
51/// Generates a contract Client for a given contract.
52/// It is expected that the name should be the same as the published contract or a contract in your current workspace.
53///
54/// # Panics
55///
56/// This function may panic in the following situations:
57/// - If `loam_build::get_target_dir()` fails to retrieve the target directory
58/// - If the input tokens cannot be parsed as a valid identifier
59/// - If the directory path cannot be canonicalized
60/// - If the canonical path cannot be converted to a string
61#[proc_macro]
62pub fn import_contract(tokens: TokenStream) -> TokenStream {
63    let cargo_file = manifest();
64    let mut dir = loam_build::get_target_dir(&cargo_file)
65        .unwrap()
66        .join(tokens.to_string());
67    let name = syn::parse::<syn::Ident>(tokens).expect("The input must be a valid identifier");
68    dir.set_extension("wasm");
69    let binding = dir.canonicalize().unwrap();
70    let file = binding.to_str().unwrap();
71    quote! {
72        mod #name {
73            use loam_sdk::soroban_sdk;
74            loam_sdk::soroban_sdk::contractimport!(file = #file);
75        }
76    }
77    .into()
78}
79
80/// Generates a contract made up of subcontracts
81/// ```ignore
82/// #[derive_contract(Core(Admin), Postable(StatusMessage))]
83/// pub struct Contract;
84/// ```
85/// Generates
86///
87/// ```ignore
88/// pub struct Contract;
89/// impl Postable for Contract {
90///     type Impl = StatusMessage;
91/// }
92/// impl Core for Contract {
93///     type Impl = Admin;
94/// }
95/// #[loam_sdk::soroban_sdk::contract]
96/// struct SorobanContract__;
97///
98/// #[loam_sdk::soroban_sdk::contract]
99/// impl SorobanContract__ {
100///  // Postable and Core methods exposed
101/// }
102///
103/// ```
104///
105/// # Panics
106/// This function may panic if the input tokens cannot be parsed as a valid Rust item.
107///
108#[proc_macro_attribute]
109pub fn derive_contract(args: TokenStream, item: TokenStream) -> TokenStream {
110    let parsed: Item = syn::parse(item.clone()).expect("failed to parse Item");
111    derive_contract_impl(proc_macro2::TokenStream::from(args), parsed).into()
112}
113
114/// Generates a contract Client for a given asset.
115/// It is expected that the name of an asset, e.g. "native" or "USDC:G1...."
116///
117/// # Panics
118///
119#[proc_macro]
120pub fn stellar_asset(input: TokenStream) -> TokenStream {
121    // Parse the input as a string literal
122    let input_str = syn::parse_macro_input!(input as syn::LitStr);
123    let network = std::env::var("STELLAR_NETWORK").unwrap_or_else(|_| "local".to_owned());
124    let asset = util::parse_asset_literal(&input_str, &network);
125
126    // Return the generated code as a TokenStream
127    asset.into()
128}
129
130#[proc_macro_attribute]
131pub fn loamstorage(_attr: TokenStream, item: TokenStream) -> TokenStream {
132    syn::parse::<Item>(item)
133        .and_then(storage::from_item)
134        .map_or_else(|e| e.to_compile_error().into(), Into::into)
135}