Skip to main content

neo_macros/
lib.rs

1// Copyright (c) 2025 R3E Network
2// Licensed under the MIT License
3
4//! Neo N3 Macros
5//!
6//! This crate provides procedural macros for Neo N3 smart contract development.
7
8use proc_macro::TokenStream;
9use syn::{parse_macro_input, DeriveInput, ItemFn, LitStr};
10
11// Module declarations - these are helper modules, not proc macros
12mod codegen;
13mod expand;
14mod parse;
15
16/// Neo N3 Contract macro
17///
18/// This macro generates the necessary boilerplate for a Neo N3 smart contract.
19///
20/// # Example
21///
22/// ```ignore,neo_devpack
23/// use neo_devpack::*;
24///
25/// #[neo_contract]
26/// pub struct MyContract {
27///     name: NeoString,
28///     value: NeoInteger,
29/// }
30///
31/// impl MyContract {
32///     #[neo_method]
33///     pub fn get_name(&self) -> NeoResult<NeoString> {
34///         Ok(self.name.clone())
35///     }
36///
37///     #[neo_method]
38///     pub fn set_value(&mut self, value: NeoInteger) -> NeoResult<()> {
39///         self.value = value;
40///         Ok(())
41///     }
42/// }
43/// ```
44#[proc_macro_attribute]
45pub fn neo_contract(_args: TokenStream, input: TokenStream) -> TokenStream {
46    let input = parse_macro_input!(input as DeriveInput);
47    expand::neo_contract(input).into()
48}
49
50/// Neo N3 Method macro
51///
52/// This macro marks a function as a Neo N3 contract method.
53///
54/// # Example
55///
56/// ```ignore
57/// #[neo_method]
58/// pub fn my_method(&self, arg: NeoInteger) -> NeoResult<NeoString> {
59///     // Method implementation
60///     Ok(NeoString::from_str("Hello, Neo!"))
61/// }
62/// ```
63#[proc_macro_attribute]
64pub fn neo_method(_args: TokenStream, input: TokenStream) -> TokenStream {
65    let input = parse_macro_input!(input as ItemFn);
66    expand::neo_method(input).into()
67}
68
69/// Neo N3 Storage macro
70///
71/// This macro generates storage operations for a Neo N3 contract.
72///
73/// # Example
74///
75/// ```ignore
76/// #[neo_storage]
77/// pub struct MyStorage {
78///     pub value: NeoInteger,
79///     pub name: NeoString,
80/// }
81/// ```
82#[proc_macro_attribute]
83pub fn neo_storage(_args: TokenStream, input: TokenStream) -> TokenStream {
84    let input = parse_macro_input!(input as DeriveInput);
85    expand::neo_storage(input).into()
86}
87
88/// Neo N3 Entry Point macro
89///
90/// This macro marks a function as a Neo N3 contract entry point.
91///
92/// # Example
93///
94/// ```ignore
95/// #[neo_entry]
96/// pub fn deploy() -> NeoResult<()> {
97///     // Deployment logic
98///     Ok(())
99/// }
100/// ```
101#[proc_macro_attribute]
102pub fn neo_entry(_args: TokenStream, input: TokenStream) -> TokenStream {
103    let input_fn = parse_macro_input!(input as ItemFn);
104    expand::neo_entry(input_fn).into()
105}
106
107/// Neo N3 Test macro
108///
109/// This macro generates test functions for a Neo N3 contract.
110///
111/// # Example
112///
113/// ```ignore
114/// #[neo_test]
115/// pub fn test_my_contract() {
116///     let contract = MyContract::new();
117///     assert_eq!(contract.get_name().unwrap(), NeoString::from_str("MyContract"));
118/// }
119/// ```
120#[proc_macro_attribute]
121pub fn neo_test(_args: TokenStream, input: TokenStream) -> TokenStream {
122    let input = parse_macro_input!(input as ItemFn);
123    expand::neo_test(input).into()
124}
125
126/// Neo N3 Benchmark macro
127///
128/// This macro generates benchmark functions for a Neo N3 contract.
129///
130/// # Example
131///
132/// ```ignore
133/// #[neo_bench]
134/// pub fn bench_my_contract(b: &mut Bencher) {
135///     b.iter(|| {
136///         let contract = MyContract::new();
137///         contract.get_name().unwrap()
138///     });
139/// }
140/// ```
141#[proc_macro_attribute]
142pub fn neo_bench(_args: TokenStream, input: TokenStream) -> TokenStream {
143    let input = parse_macro_input!(input as ItemFn);
144    expand::neo_bench(input).into()
145}
146
147//
148// ============================================================================
149// Proc macros moved from submodules (Rust requires them to be in lib.rs root)
150// ============================================================================
151//
152
153// ---- From events.rs ----
154
155/// Neo N3 Event macro
156///
157/// This macro generates the necessary boilerplate for a Neo N3 contract event.
158///
159/// # Example
160///
161/// ```ignore,neo_devpack
162/// #[neo_event]
163/// pub struct TransferEvent {
164///     pub from: NeoByteString,
165///     pub to: NeoByteString,
166///     pub amount: NeoInteger,
167/// }
168/// ```
169///
170/// The macro generates:
171/// - An `emit()` method that notifies the runtime with the event data
172/// - Manifest metadata describing the event parameters
173#[proc_macro_attribute]
174pub fn neo_event(_args: TokenStream, input: TokenStream) -> TokenStream {
175    let input = parse_macro_input!(input as DeriveInput);
176    match expand::neo_event(input) {
177        Ok(tokens) => tokens.into(),
178        Err(err) => err.to_compile_error().into(),
179    }
180}
181
182// ---- From manifest.rs ----
183
184/// Neo N3 Manifest Overlay macro
185///
186/// Embed a JSON manifest fragment as a Wasm custom section.
187///
188/// # Example
189///
190/// ```ignore
191/// neo_manifest_overlay!(r#"{"name": "MyContract", "version": "1.0.0"}"#);
192/// ```
193#[proc_macro]
194pub fn neo_manifest_overlay(input: TokenStream) -> TokenStream {
195    let literal = parse_macro_input!(input as LitStr);
196    expand::neo_manifest_overlay(&literal).into()
197}
198
199// ---- From permissions.rs ----
200
201/// Declare manifest permissions and embed them as a custom section.
202///
203/// # Example
204///
205/// ```ignore
206/// neo_permission!("0x1234567890abcdef", ["method1", "method2"]);
207/// ```
208#[proc_macro]
209pub fn neo_permission(input: TokenStream) -> TokenStream {
210    let args = parse_macro_input!(input as parse::PermissionArgs);
211    let contract = args.contract.value();
212    let methods: Vec<String> = args.methods.into_iter().map(|lit| lit.value()).collect();
213    expand::neo_permission(contract, methods).into()
214}
215
216/// Declare trusted contracts for the contract manifest.
217///
218/// # Example
219///
220/// ```ignore
221/// neo_trusts!(["0x1234567890abcdef", "0xfedcba0987654321"]);
222/// ```
223#[proc_macro]
224pub fn neo_trusts(input: TokenStream) -> TokenStream {
225    let list = parse_macro_input!(input as parse::StringList);
226    let trusts: Vec<String> = list.items.into_iter().map(|lit| lit.value()).collect();
227    expand::neo_trusts(trusts).into()
228}
229
230// ---- From safe_methods.rs ----
231
232/// Declare safe methods for the contract manifest.
233///
234/// # Example
235///
236/// ```ignore
237/// neo_safe_methods!(["balanceOf", "symbol", "decimals"]);
238/// ```
239#[proc_macro]
240pub fn neo_safe_methods(input: TokenStream) -> TokenStream {
241    let list = parse_macro_input!(input as parse::StringList);
242    let methods: Vec<String> = list.items.into_iter().map(|lit| lit.value()).collect();
243    expand::neo_safe_methods(methods).into()
244}
245
246/// Mark a single exported function as safe in the manifest.
247///
248/// # Example
249///
250/// ```ignore
251/// #[neo_safe]
252/// pub fn balance_of(owner: NeoByteString) -> NeoInteger {
253///     // Implementation
254/// }
255/// ```
256#[proc_macro_attribute]
257pub fn neo_safe(_args: TokenStream, input: TokenStream) -> TokenStream {
258    let func = parse_macro_input!(input as ItemFn);
259    expand::neo_safe(func).into()
260}
261
262// ---- From standards.rs ----
263
264/// Declare supported standards for the contract manifest.
265///
266/// # Example
267///
268/// ```ignore
269/// neo_supported_standards!(["NEP-17", "NEP-11"]);
270/// ```
271#[proc_macro]
272pub fn neo_supported_standards(input: TokenStream) -> TokenStream {
273    let list = parse_macro_input!(input as parse::StringList);
274    let standards: Vec<String> = list.items.into_iter().map(|lit| lit.value()).collect();
275    expand::neo_supported_standards(standards).into()
276}
277
278/// Neo N3 Documentation macro
279///
280/// This macro generates documentation for a Neo N3 contract.
281///
282/// # Example
283///
284/// ```ignore
285/// #[neo_doc]
286/// pub struct MyContract {
287///     /// The name of the contract
288///     pub name: NeoString,
289///     /// The value of the contract
290///     pub value: NeoInteger,
291/// }
292/// ```
293#[proc_macro_attribute]
294pub fn neo_doc(_args: TokenStream, input: TokenStream) -> TokenStream {
295    let input = parse_macro_input!(input as DeriveInput);
296    expand::neo_doc(input).into()
297}
298
299/// Neo N3 Configuration macro
300///
301/// This macro generates configuration for a Neo N3 contract.
302///
303/// # Example
304///
305/// ```ignore
306/// #[neo_config]
307/// pub struct MyConfig {
308///     pub max_value: NeoInteger,
309///     pub min_value: NeoInteger,
310/// }
311/// ```
312#[proc_macro_attribute]
313pub fn neo_config(_args: TokenStream, input: TokenStream) -> TokenStream {
314    let input = parse_macro_input!(input as DeriveInput);
315    expand::neo_config(input).into()
316}
317
318/// Neo N3 Validation macro
319///
320/// This macro generates validation for a Neo N3 contract.
321///
322/// # Example
323///
324/// ```ignore
325/// #[neo_validate]
326/// pub fn validate_value(value: NeoInteger) -> NeoResult<()> {
327///     if value < NeoInteger::zero() {
328///         return Err(NeoError::InvalidArgument);
329///     }
330///     Ok(())
331/// }
332/// ```
333#[proc_macro_attribute]
334pub fn neo_validate(_args: TokenStream, input: TokenStream) -> TokenStream {
335    let input = parse_macro_input!(input as ItemFn);
336    expand::neo_validate(input).into()
337}
338
339/// Neo N3 Serialization macro
340///
341/// This macro generates serialization for a Neo N3 contract.
342///
343/// # Example
344///
345/// ```ignore
346/// #[neo_serialize]
347/// pub struct MyData {
348///     pub value: NeoInteger,
349///     pub name: NeoString,
350/// }
351/// ```
352#[proc_macro_attribute]
353pub fn neo_serialize(_args: TokenStream, input: TokenStream) -> TokenStream {
354    let input = parse_macro_input!(input as DeriveInput);
355    expand::neo_serialize(input).into()
356}
357
358/// Neo N3 Error macro
359///
360/// This macro generates error handling for a Neo N3 contract.
361///
362/// # Example
363///
364/// ```ignore
365/// #[neo_error]
366/// pub enum MyError {
367///     InvalidValue,
368///     InvalidName,
369/// }
370/// ```
371#[proc_macro_attribute]
372pub fn neo_error(_args: TokenStream, input: TokenStream) -> TokenStream {
373    let input = parse_macro_input!(input as DeriveInput);
374    expand::neo_error(input).into()
375}