Skip to main content

junobuild_macros/
lib.rs

1#![doc = include_str!("../README.md")]
2
3extern crate proc_macro;
4
5#[doc(hidden)]
6mod error;
7#[doc(hidden)]
8mod functions;
9#[doc(hidden)]
10mod hooks;
11
12use functions::derive::derive_json_data;
13use hooks::parser::{hook_macro, Hook};
14use proc_macro::TokenStream;
15
16/// The `on_set_doc` function is a procedural macro attribute for hooking into the `OnSetDoc` event.
17/// It allows you to define custom logic to be executed when a document is set.
18///
19/// Example:
20///
21/// ```rust
22/// #[on_set_doc]
23/// async fn on_set_doc(context: OnSetDocContext) -> Result<(), String> {
24///     // Your hook logic here
25/// }
26/// ```
27///
28/// When no attributes are provided, the hook is triggered for any document set within any collection.
29/// You can scope the events to a particular list of collections.
30///
31/// Example:
32/// ```rust
33/// #[on_set_doc(collections = ["demo"])]
34/// async fn on_set_doc(context: OnSetDocContext) -> Result<(), String> {
35///     // Your hook logic here
36/// }
37/// ```
38///
39/// The attributes accept a list of comma-separated collections. If the attribute array is left empty, the hook will never be called.
40///
41#[proc_macro_attribute]
42pub fn on_set_doc(attr: TokenStream, item: TokenStream) -> TokenStream {
43    hook_macro(Hook::OnSetDoc, attr, item)
44}
45
46/// The `on_set_many_docs` function is a procedural macro attribute for hooking into the `OnSetManyDocs` event.
47/// It allows you to define custom logic to be executed when multiple documents are set.
48///
49/// Example:
50///
51/// ```rust
52/// #[on_set_many_docs]
53/// async fn on_set_many_docs(context: OnSetManyDocsContext) -> Result<(), String> {
54///     // Your hook logic here
55/// }
56/// ```
57///
58/// When no attributes are provided, the hook is triggered for any document set within any collection.
59/// You can scope the events to a particular list of collections.
60///
61/// Example:
62/// ```rust
63/// #[on_set_many_docs(collections = ["demo"])]
64/// async fn on_set_many_docs(context: OnSetManyDocsContext) -> Result<(), String> {
65///     // Your hook logic here
66/// }
67/// ```
68///
69/// The attributes accept a list of comma-separated collections. If the attribute array is left empty, the hook will never be called.
70///
71#[proc_macro_attribute]
72pub fn on_set_many_docs(attr: TokenStream, item: TokenStream) -> TokenStream {
73    hook_macro(Hook::OnSetManyDocs, attr, item)
74}
75
76/// The `on_delete_doc` function is a procedural macro attribute for hooking into the `OnDeleteDoc` event.
77/// It allows you to define custom logic to be executed when a document is deleted.
78///
79/// Example:
80///
81/// ```rust
82/// #[on_delete_doc]
83/// async fn on_delete_doc(context: OnDeleteDocContext) -> Result<(), String> {
84///     // Your hook logic here
85/// }
86/// ```
87///
88/// When no attributes are provided, the hook is triggered for any document set within any collection.
89/// You can scope the events to a particular list of collections.
90///
91/// Example:
92/// ```rust
93/// #[on_delete_doc(collections = ["demo"])]
94/// async fn on_delete_doc(context: OnDeleteDocContext) -> Result<(), String> {
95///     // Your hook logic here
96/// }
97/// ```
98///
99/// The attributes accept a list of comma-separated collections. If the attribute array is left empty, the hook will never be called.
100///
101#[proc_macro_attribute]
102pub fn on_delete_doc(attr: TokenStream, item: TokenStream) -> TokenStream {
103    hook_macro(Hook::OnDeleteDoc, attr, item)
104}
105
106/// The `on_delete_many_docs` function is a procedural macro attribute for hooking into the `OnDeleteManyDocs` event.
107/// It allows you to define custom logic to be executed when multiple documents are deleted.
108///
109/// Example:
110///
111/// ```rust
112/// #[on_delete_many_docs]
113/// async fn on_delete_many_docs(context: OnDeleteManyDocsContext) -> Result<(), String> {
114///     // Your hook logic here
115/// }
116/// ```
117///
118/// When no attributes are provided, the hook is triggered for any document set within any collection.
119/// You can scope the events to a particular list of collections.
120///
121/// Example:
122/// ```rust
123/// #[on_delete_many_docs(collections = ["demo"])]
124/// async fn on_delete_many_docs(context: OnDeleteManyDocsContext) -> Result<(), String> {
125///     // Your hook logic here
126/// }
127/// ```
128///
129/// The attributes accept a list of comma-separated collections. If the attribute array is left empty, the hook will never be called.
130///
131#[proc_macro_attribute]
132pub fn on_delete_many_docs(attr: TokenStream, item: TokenStream) -> TokenStream {
133    hook_macro(Hook::OnDeleteManyDocs, attr, item)
134}
135
136/// The `on_delete_filtered_docs` function is a procedural macro attribute for hooking into the `OnDeleteFilteredDocs` event.
137/// It allows you to define custom logic to be executed when documents are deleted based on specific filter criteria.
138///
139/// Example:
140///
141/// ```rust
142/// #[on_delete_filtered_docs]
143/// async fn on_delete_filtered_docs(context: OnDeleteFilteredDocsContext) -> Result<(), String> {
144///     // Your hook logic here
145/// }
146/// ```
147///
148/// You can scope the events to a particular list of collections, making the hook more selective.
149///
150/// Example:
151/// ```rust
152/// #[on_delete_filtered_docs(collections = ["demo"])]
153/// async fn on_delete_filtered_docs(context: OnDeleteFilteredDocsContext) -> Result<(), String> {
154///     // Your hook logic here
155/// }
156/// ```
157///
158/// The attributes accept a list of comma-separated collections. If the attribute array is left empty, the hook will never be called.
159///
160/// # Parameters
161/// - `collections`: An optional list of collections to limit the scope of the hook.
162/// - `context`: An instance of `OnDeleteFilteredDocsContext` containing information about the deletion event.
163///
164/// # Returns
165/// - `Ok(())`: Indicates successful execution of the hook logic.
166/// - `Err(String)`: An error message if the hook logic encounters issues.
167///
168#[proc_macro_attribute]
169pub fn on_delete_filtered_docs(attr: TokenStream, item: TokenStream) -> TokenStream {
170    hook_macro(Hook::OnDeleteFilteredDocs, attr, item)
171}
172
173/// The `on_upload_asset` function is a procedural macro attribute for hooking into the `OnUploadAsset` event.
174/// It allows you to define custom logic to be executed when an asset is uploaded.
175///
176/// Example:
177///
178/// ```rust
179/// #[on_upload_asset]
180/// async fn on_upload_asset(context: OnUploadAssetContext) -> Result<(), String> {
181///     // Your hook logic here
182/// }
183/// ```
184///
185/// When no attributes are provided, the hook is triggered for any asset upload within any collection.
186/// You can scope the events to a particular list of collections.
187///
188/// Example:
189/// ```rust
190/// #[on_upload_asset(collections = ["demo"])]
191/// async fn on_upload_asset(context: OnUploadAssetContext) -> Result<(), String> {
192///     // Your hook logic here
193/// }
194/// ```
195///
196/// The attributes accept a list of comma-separated collections. If the attribute array is left empty, the hook will never be called.
197///
198#[proc_macro_attribute]
199pub fn on_upload_asset(attr: TokenStream, item: TokenStream) -> TokenStream {
200    hook_macro(Hook::OnUploadAsset, attr, item)
201}
202
203/// The `on_delete_asset` function is a procedural macro attribute for hooking into the `OnDeleteAsset` event.
204/// It allows you to define custom logic to be executed when an asset is deleted.
205///
206/// Example:
207///
208/// ```rust
209/// #[on_delete_asset]
210/// async fn on_delete_asset(context: OnDeleteAssetContext) -> Result<(), String> {
211///     // Your hook logic here
212/// }
213/// ```
214///
215/// When no attributes are provided, the hook is triggered for any asset deletion within any collection.
216/// You can scope the events to a particular list of collections.
217///
218/// Example:
219/// ```rust
220/// #[on_delete_asset(collections = ["demo"])]
221/// async fn on_delete_asset(context: OnDeleteAssetContext) -> Result<(), String> {
222///     // Your hook logic here
223/// }
224/// ```
225///
226/// The attributes accept a list of comma-separated collections. If the attribute array is left empty, the hook will never be called.
227///
228#[proc_macro_attribute]
229pub fn on_delete_asset(attr: TokenStream, item: TokenStream) -> TokenStream {
230    hook_macro(Hook::OnDeleteAsset, attr, item)
231}
232
233/// The `on_delete_many_assets` function is a procedural macro attribute for hooking into the `OnDeleteManyAssets` event.
234/// It allows you to define custom logic to be executed when multiple assets are deleted.
235///
236/// Example:
237///
238/// ```rust
239/// #[on_delete_many_assets]
240/// async fn on_delete_many_assets(context: OnDeleteManyAssetsContext) -> Result<(), String> {
241///     // Your hook logic here
242/// }
243/// ```
244///
245/// When no attributes are provided, the hook is triggered for any asset deletion within any collection.
246/// You can scope the events to a particular list of collections.
247///
248/// Example:
249/// ```rust
250/// #[on_delete_many_assets(collections = ["demo"])]
251/// async fn on_delete_many_assets(context: OnDeleteManyAssetsContext) -> Result<(), String> {
252///     // Your hook logic here
253/// }
254/// ```
255///
256/// The attributes accept a list of comma-separated collections. If the attribute array is left empty, the hook will never be called.
257///
258#[proc_macro_attribute]
259pub fn on_delete_many_assets(attr: TokenStream, item: TokenStream) -> TokenStream {
260    hook_macro(Hook::OnDeleteManyAssets, attr, item)
261}
262
263/// The `on_delete_filtered_assets` function is a procedural macro attribute for hooking into the `OnDeleteFilteredAssets` event.
264/// It allows you to define custom logic to be executed when assets are deleted based on specific filter criteria.
265///
266/// Example:
267///
268/// ```rust
269/// #[on_delete_filtered_assets]
270/// async fn on_delete_filtered_assets(context: OnDeleteFilteredAssetsContext) -> Result<(), String> {
271///     // Your hook logic here
272/// }
273/// ```
274///
275/// You can scope the events to a particular list of collections, making the hook more selective.
276///
277/// Example:
278/// ```rust
279/// #[on_delete_filtered_assets(collections = ["assets_collection"])]
280/// async fn on_delete_filtered_assets(context: OnDeleteFilteredAssetsContext) -> Result<(), String> {
281///     // Your hook logic here
282/// }
283/// ```
284///
285/// The attributes accept a list of comma-separated collections. If the attribute array is left empty, the hook will never be called.
286///
287/// # Parameters
288/// - `collections`: An optional list of collections to limit the scope of the hook.
289/// - `context`: An instance of `OnDeleteFilteredAssetsContext` containing information about the deletion event.
290///
291/// # Returns
292/// - `Ok(())`: Indicates successful execution of the hook logic.
293/// - `Err(String)`: An error message if the hook logic encounters issues.
294///
295#[proc_macro_attribute]
296pub fn on_delete_filtered_assets(attr: TokenStream, item: TokenStream) -> TokenStream {
297    hook_macro(Hook::OnDeleteFilteredAssets, attr, item)
298}
299
300/// The `assert_set_doc` function is a procedural macro attribute for asserting conditions before setting a document.
301/// It enables you to define custom validation logic to be executed prior to a document creation or update.
302///
303/// Example:
304///
305/// ```rust
306/// #[assert_set_doc]
307/// fn assert_set_doc(context: AssertSetDocContext) -> Result<(), String> {
308///     // Your assertion logic here
309/// }
310/// ```
311///
312/// When no attributes are provided, the assertion logic is applied to any document set within any collection.
313/// You can scope the assertion to a particular list of collections.
314///
315/// Example:
316/// ```rust
317/// #[assert_set_doc(collections = ["demo"])]
318/// fn assert_set_doc(context: AssertSetDocContext) -> Result<(), String> {
319///     // Your assertion logic here
320/// }
321/// ```
322///
323/// The attributes accept a list of comma-separated collections. If the attribute array is left empty, the assertion will always be evaluated.
324///
325#[proc_macro_attribute]
326pub fn assert_set_doc(attr: TokenStream, item: TokenStream) -> TokenStream {
327    hook_macro(Hook::AssertSetDoc, attr, item)
328}
329
330/// The `assert_delete_doc` function is a procedural macro attribute for asserting conditions before deleting a document.
331/// It enables you to define custom validation logic to be executed prior to a document deletion.
332///
333/// Example:
334///
335/// ```rust
336/// #[assert_delete_doc]
337/// fn assert_delete_doc(context: AssertDeleteDocContext) -> Result<(), String> {
338///     // Your assertion logic here
339/// }
340/// ```
341///
342/// When no attributes are provided, the assertion logic is applied to any document delete within any collection.
343/// You can scope the assertion to a particular list of collections.
344///
345/// Example:
346/// ```rust
347/// #[assert_delete_doc(collections = ["demo"])]
348/// fn assert_delete_doc(context: AssertDeleteDocContext) -> Result<(), String> {
349///     // Your assertion logic here, specific to the "demo" collection
350/// }
351/// ```
352///
353/// The attributes accept a list of comma-separated collections. If the attribute array is left empty, the assertion will always be evaluated.
354///
355#[proc_macro_attribute]
356pub fn assert_delete_doc(attr: TokenStream, item: TokenStream) -> TokenStream {
357    hook_macro(Hook::AssertDeleteDoc, attr, item)
358}
359
360/// The `assert_upload_asset` function is a procedural macro attribute for asserting conditions before committing the upload of an asset.
361/// It enables you to define custom validation logic to be executed prior to an asset being committed.
362///
363/// Example:
364///
365/// ```rust
366/// #[assert_upload_asset]
367/// fn assert_upload_asset(context: AssertUploadAssetContext) -> Result<(), String> {
368///     // Your assertion logic here
369/// }
370/// ```
371///
372/// When no attributes are provided, the assertion logic is applied to any asset upload within any collection.
373/// You can scope the assertion to a particular list of collections.
374///
375/// Example:
376/// ```rust
377/// #[assert_upload_asset(collections = ["assets"])]
378/// fn juno_assert_upload_asset(context: AssertUploadAssetContext) -> Result<(), String> {
379///     // Your assertion logic here, specific to the "assets" collection
380/// }
381/// ```
382///
383/// The attributes accept a list of comma-separated collections. If the attribute array is left empty, the assertion will always be evaluated.
384///
385#[proc_macro_attribute]
386pub fn assert_upload_asset(attr: TokenStream, item: TokenStream) -> TokenStream {
387    hook_macro(Hook::AssertUploadAsset, attr, item)
388}
389
390/// The `assert_delete_asset` function is a procedural macro attribute for asserting conditions before deleting an asset.
391/// It enables you to define custom validation logic to be executed prior to an asset being deleted.
392///
393/// Example:
394///
395/// ```rust
396/// #[assert_delete_asset]
397/// fn assert_delete_asset(context: AssertDeleteAssetContext) -> Result<(), String> {
398///     // Your assertion logic here
399/// }
400/// ```
401///
402/// When no attributes are provided, the assertion logic is applied to any asset deletion within any collection.
403/// You can scope the assertion to a particular list of collections.
404///
405/// Example:
406/// ```rust
407/// #[assert_delete_asset(collections = ["assets"])]
408/// fn juno_assert_delete_asset(context: AssertDeleteAssetContext) -> Result<(), String> {
409///     // Your assertion logic here, specific to the "assets" collection
410/// }
411/// ```
412///
413/// The attributes accept a list of comma-separated collections. If the attribute array is left empty, the assertion will always be evaluated.
414///
415#[proc_macro_attribute]
416pub fn assert_delete_asset(attr: TokenStream, item: TokenStream) -> TokenStream {
417    hook_macro(Hook::AssertDeleteAsset, attr, item)
418}
419
420/// The `on_post_upgrade` function is a procedural macro attribute for hooking into the `OnPostUpgrade` event.
421/// It allows you to define custom logic to be executed after a satellite upgrade.
422///
423/// Example:
424///
425/// ```rust
426/// #[on_post_upgrade]
427/// fn on_post_upgrade() {
428///     // Your post-upgrade logic here
429/// }
430/// ```
431///
432#[proc_macro_attribute]
433pub fn on_post_upgrade(attr: TokenStream, item: TokenStream) -> TokenStream {
434    hook_macro(Hook::OnPostUpgrade, attr, item)
435}
436
437/// The `on_init` function is a procedural macro attribute for hooking into the `OnInit` event.
438/// It allows you to define custom logic to be executed after a satellite is initialized.
439///
440/// Example:
441///
442/// ```rust
443/// #[on_init]
444/// fn on_init() {
445///     // Your post-init logic here
446/// }
447/// ```
448///
449#[proc_macro_attribute]
450pub fn on_init(attr: TokenStream, item: TokenStream) -> TokenStream {
451    hook_macro(Hook::OnInit, attr, item)
452}
453
454/// The `on_post_upgrade_sync` function is a procedural macro attribute for hooking into the `OnPostUpgrade` event.
455/// Unlike `on_post_upgrade`, this variant **executes synchronously** and is intended for advanced use cases
456/// where immediate execution is required.
457///
458/// This macro should only be used in scenarios where deferred execution (via async hooks) is **not an option**.
459/// Regular users should use `#[on_post_upgrade]` instead.
460///
461/// # Warning ⚠️
462/// - This function **executes immediately** during a satellite upgrade.
463/// - It **bypasses** the usual async execution model, which may lead to **unexpected behavior** if used improperly.
464/// - Any error in this function will cause the upgrade to fail!!!
465/// - If the upgrade fails, the satellite might become unresponsive and lose its data.
466/// - **Developers should prefer `on_post_upgrade` unless they explicitly need synchronous behavior.**
467///
468/// Furthermore, note that the random number generator or other capabilities might not have been initialized at this point.
469///
470/// # Example (Restricted Usage)
471///
472/// ```rust
473/// #[on_post_upgrade_sync]
474/// fn on_post_upgrade_sync() {
475///     // Perform necessary actions immediately on upgrade
476/// }
477/// ```
478///
479/// **Note:** This function is hidden from public documentation to discourage general usage.
480#[doc(hidden)]
481#[proc_macro_attribute]
482pub fn on_post_upgrade_sync(attr: TokenStream, item: TokenStream) -> TokenStream {
483    hook_macro(Hook::OnPostUpgradeSync, attr, item)
484}
485
486/// The `on_init_sync` function is a procedural macro attribute for hooking into the `OnInit` event.
487/// It serves the same purpose as `on_init`, but **executes synchronously**, ensuring that initialization
488/// logic is run **immediately** instead of being deferred.
489///
490/// This function is intended for **special cases only** where an immediate initialization
491/// step is necessary before any asynchronous tasks are triggered.
492///
493/// # Warning ⚠️
494/// - This function **runs immediately** at initialization time.
495/// - It **bypasses deferred execution**, meaning long-running operations **may slow down startup**.
496/// - Regular users **should use `on_init` instead**, unless there's a strict requirement for synchronous behavior.
497///
498/// Furthermore, note that the random number generator or other capabilities might not have been initialized at this point.
499///
500/// # Example (Restricted Usage)
501///
502/// ```rust
503/// #[on_init_sync]
504/// fn on_init_sync() {
505///     // This runs synchronously before any async operations are triggered
506/// }
507/// ```
508///
509/// **Note:** This function is hidden from public documentation to prevent unintended usage.
510#[doc(hidden)]
511#[proc_macro_attribute]
512pub fn on_init_sync(attr: TokenStream, item: TokenStream) -> TokenStream {
513    hook_macro(Hook::OnInitSync, attr, item)
514}
515
516/// The `on_init_random_seed` function is a procedural macro attribute for hooking into the
517/// `OnInitRandomSeed` event. It allows you to define custom logic to be executed after
518/// the satellite has initialized the random seed.
519///
520/// Example:
521///
522/// ```rust
523/// #[on_init_random_seed]
524/// fn on_init_random_seed() {
525///     // Your post-initialization logic after random seed setup
526/// }
527/// ```
528///
529#[proc_macro_attribute]
530pub fn on_init_random_seed(attr: TokenStream, item: TokenStream) -> TokenStream {
531    hook_macro(Hook::OnInitRandomSeed, attr, item)
532}
533
534/// Derive macro that generates JS-compatible JSON serialization for Juno serverless function structs.
535///
536/// Automatically maps Candid types to their `JsonData*` equivalents (`Principal` → `JsonDataPrincipal`,
537/// `Vec<u8>` → `JsonDataUint8Array`, `u64` → `JsonDataBigInt`) and generates:
538/// - `into_json_data()` — serializes the struct to bytes for passing to the JS runtime
539/// - `from_json_data()` — deserializes bytes from the JS runtime back into the struct
540///
541/// # Example
542///
543/// ```rust
544/// #[derive(CandidType, Serialize, Deserialize, JsonData)]
545/// pub struct InputArgs {
546///     value: Principal,
547/// }
548///
549/// #[derive(CandidType, Serialize, Deserialize, JsonData)]
550/// pub struct OutputArgs {
551///     value: Principal,
552///     text: String,
553/// }
554///
555/// // Generated: InputArgsJsonData/OutputArgsJsonData structs + From impls + into_json_data() + from_json_data()
556/// ```
557#[proc_macro_derive(JsonData, attributes(json_data))]
558pub fn json_data(input: TokenStream) -> TokenStream {
559    derive_json_data(input)
560}