odra_proc_macros/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use syn::{parse_macro_input, DeriveInput};
5
6mod event;
7mod execution_error;
8mod external_contract;
9mod instance;
10mod map;
11mod module;
12mod odra_error;
13mod odra_type;
14
15/// Core element of the Odra framework, entry point for writing smart contracts.
16///
17/// Each module consists of two parts:
18/// 1. Module definition - a struct which composition of stored values (Variables and Mappings)
19/// and modules.
20/// 2. Module implementation - an implementation block.
21///
22/// The macro produces all the required code to use the module as a standalone smart contract.
23///
24///
25/// # Examples
26///
27/// ```
28/// use odra;
29/// # extern crate alloc;
30///
31/// #[odra::module]
32/// pub struct Flipper {
33///     value: odra::Variable<bool>,
34/// }
35///
36/// #[odra::module]
37/// impl Flipper {
38///     #[odra(init)]
39///     pub fn initial_settings(&mut self, value: bool) {
40///         self.value.set(value);
41///     }
42///
43///     pub fn flip(&mut self) {
44///         self.value.set(!self.get());
45///     }
46///
47///     pub fn get(&self) -> bool {
48///         self.value.get_or_default()
49///     }
50/// }
51/// ```
52#[proc_macro_attribute]
53pub fn module(attr: TokenStream, item: TokenStream) -> TokenStream {
54    module::generate_code(attr, item).into()
55}
56
57/// Provides implementation of [Instance](../odra/instance/trait.Instance.html) trait.
58#[proc_macro_derive(Instance)]
59pub fn derive_instance(input: TokenStream) -> TokenStream {
60    instance::generate_code(parse_macro_input!(input as DeriveInput)).into()
61}
62
63/// Provides implementation of a reference to an external contract.
64///
65/// If you don't have access to the contract source code, but want to call it,
66/// you can create a reference to it and interact exactly the same way as with a contract
67/// written using [macro@module] macro.
68///
69/// # Examples
70///
71/// ```
72/// use odra;
73///
74/// #[odra::external_contract]
75/// pub trait Getter {
76///     fn get(&self) -> u32;
77/// }
78///
79/// let contract_address = odra::types::Address::try_from(&[1u8; 33]).unwrap();
80/// // in your contract
81/// let getter = GetterRef::at(&contract_address);
82/// // let value = getter.get();
83/// ```
84#[proc_macro_attribute]
85pub fn external_contract(attr: TokenStream, item: TokenStream) -> TokenStream {
86    external_contract::generate_code(attr, item).into()
87}
88
89/// Implements boilerplate code required by an event.
90///
91/// Implements [Event](../odra_types/event/trait.OdraEvent.html) trait, and serialization/deserialization.
92///
93/// # Examples
94///
95/// ```
96/// #[derive(odra::Event)]
97/// pub struct ValueUpdated {
98///     pub value: u32,
99/// }
100///
101/// let event = ValueUpdated { value: 42 };
102///
103/// assert_eq!(&<ValueUpdated as odra::types::event::OdraEvent>::name(), "ValueUpdated");
104/// ```
105#[proc_macro_derive(Event)]
106pub fn derive_event(input: TokenStream) -> TokenStream {
107    event::generate_code(parse_macro_input!(input as DeriveInput)).into()
108}
109
110/// Implements boilerplate code required by an OdraType.
111///
112/// Implements [OdraType](../odra/types/trait.OdraType.html) trait,
113/// [OdraItem](../odra/trait.OdraItem.html) trait, and serialization/deserialization.
114#[proc_macro_derive(OdraType)]
115pub fn derive_odra_type(input: TokenStream) -> TokenStream {
116    odra_type::generate_code(parse_macro_input!(input as DeriveInput)).into()
117}
118
119/// Implements `Into<odra::types::ExecutionError>` and `Into<odra::types::OdraError>` for an error enum.
120///
121/// An enum should use a custom syntax, and each variant is mapped to n error code e.g. `Name => 1`.
122///
123/// # Examples
124///
125/// ```
126/// use odra;
127///
128/// odra::execution_error! {
129///     pub enum Error {
130///         Fatal => 1,
131///         Checked => 2,
132///     }
133/// };
134///
135/// let exec_error: odra::types::ExecutionError = Error::Fatal.into();
136/// let odra_error: odra::types::OdraError = Error::Checked.into();
137/// ```
138///
139/// Each variant must have a code.
140/// ```compile_fail
141/// use odra;
142///
143/// odra::execution_error! {
144///     pub enum Error {
145///         Fatal => 1,
146///         Checked,
147///     }
148/// };
149///
150/// ```
151///
152/// Each code must be unique.
153///
154/// ```compile_fail
155/// use odra;
156///
157/// odra::execution_error! {
158///     pub enum Error {
159///         Fatal => 1,
160///         Checked => 1,
161///     }
162/// };
163/// ```
164#[proc_macro]
165pub fn execution_error(item: TokenStream) -> TokenStream {
166    execution_error::generate_code(item).into()
167}
168
169/// Implements `Into<odra::types::OdraError>` for an error enum.
170///
171/// In most cases the [execution_error!] is preferred, but if `Into<odra::types::ExecutionError>` is
172/// implemented manually, the implementation of `Into<odra::types::OdraError>` still can be delegated to the macro.
173#[proc_macro_attribute]
174pub fn odra_error(_attr: TokenStream, item: TokenStream) -> TokenStream {
175    odra_error::generate_code(item).into()
176}
177
178/// Implements the boilerplate code required to read/write a value from/to a map.
179///
180/// To access the value in the nested map, it would be required to use a chain
181/// of `get_instance` calls. This macro provides a convenient syntax for that.
182///
183/// # Examples
184///
185/// ```
186/// use odra::{self, Mapping};
187/// # extern crate alloc;
188///
189/// #[odra::module]
190/// pub struct NestedMapping {
191///     value: Mapping<String, Mapping<String, Mapping<String, u32>>>,
192/// }
193///
194/// #[odra::module]
195/// impl NestedMapping {
196///     pub fn set(&mut self, k1: String, k2: String, k3: String, value: u32) {
197///         odra::map!(self.value[k1][k2][k3] = value);
198///     }
199///
200///     pub fn get(&self, k1: String, k2: String, k3: String) -> u32 {
201///         odra::map!(self.value[k1][k2][k3])
202///     }
203/// }
204/// ```
205#[proc_macro]
206pub fn map(item: TokenStream) -> TokenStream {
207    map::generate_code(item).into()
208}