Skip to main content

neo_macros/
lib.rs

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