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