Skip to content

Commit d09c01f

Browse files
authored
Merge pull request #115 from kinode-dao/hf/add-spawn-noop-macro
add `Spawn!()` noop macro
2 parents 9abf96d + 09cd590 commit d09c01f

File tree

1 file changed

+112
-0
lines changed

1 file changed

+112
-0
lines changed

src/lib.rs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -307,3 +307,115 @@ pub fn get_capability(issuer: &Address, params: &str) -> Option<Capability> {
307307
cap.issuer == *issuer && params == cap_params
308308
})
309309
}
310+
311+
/// The `Spawn!()` macro is defined here as a no-op.
312+
/// However, in practice, `kit build` will rewrite it during pre-processing.
313+
///
314+
/// Examples:
315+
/// ```no_run
316+
/// fn init(our: Address) {
317+
/// let parent = our.clone();
318+
/// Spawn!(|parent: Address| {
319+
/// println!("hello from {our}. I am Spawn of {parent}!");
320+
/// });
321+
/// ...
322+
/// }
323+
/// ```
324+
/// will be rewritten by `kit build` to:
325+
/// 1. Generate a new child process within the package that, here, `println!()`s,
326+
/// or, in general, executes the code given by the closure.
327+
/// 2. Replace the code lines in the parent process with [`spawn()`] to start
328+
/// the generated child and send a [`Request()`] to pass in the closure's args.
329+
/// 3. Update the relevant metadata for the package
330+
/// (i.e. `Cargo.toml`, `metadata.json`, etc.).
331+
///
332+
/// More example usage:
333+
///
334+
/// Can pass function call rather than closure:
335+
/// ```no_run
336+
/// fn init(our: Address) {
337+
/// let parent = our.clone();
338+
/// Spawn!(my_function(parent));
339+
/// ...
340+
/// }
341+
/// ```
342+
/// Nested function calls work as expected.
343+
///
344+
/// Can optionally supply subset of [`spawn()`] arguments, namely
345+
/// * name: &str,
346+
/// * on_exit: [`OnExit`],
347+
/// * request_capabilities: Vec<[`Capability`]>,
348+
/// * grant_capabilities: Vec<[`ProcessId`]>,
349+
/// * public: bool,
350+
/// for example:
351+
/// ```no_run
352+
/// fn init(our: Address) {
353+
/// let parent = our.clone();
354+
/// Spawn!(my_function(parent), name: "hello-world", public: true);
355+
/// ...
356+
/// }
357+
/// ```
358+
#[macro_export]
359+
macro_rules! Spawn {
360+
// Pattern 1: Closure with type-annotated paramters & with no options
361+
(|$($param:ident : $type:ty),+ $(,)?| $body:block) => {};
362+
363+
// Pattern 2: Function call with no options
364+
($fn_name:ident($($arg:expr),* $(,)?)) => {};
365+
366+
// Pattern 3: Closure with type-annotated paramters & with options
367+
(
368+
|$($param:ident : $type:ty),+ $(,)?| $body:block,
369+
$(
370+
$key:ident : $value:expr
371+
$(,)?
372+
)*
373+
) => {{
374+
// Validate each key at compile time using nested macro
375+
$crate::validate_spawn_args!($($key),*);
376+
377+
// Your implementation here
378+
}};
379+
380+
// Pattern 4: Function call with options
381+
(
382+
$fn_name:ident($($arg:expr),* $(,)?),
383+
$(
384+
$key:ident : $value:expr
385+
$(,)?
386+
)*
387+
) => {{
388+
// Validate each key at compile time using nested macro
389+
$crate::validate_spawn_args!($($key),*);
390+
391+
// Your implementation here
392+
}};
393+
}
394+
395+
#[macro_export]
396+
macro_rules! validate_spawn_args {
397+
// Empty case - no args to validate
398+
() => {};
399+
400+
// Validate single argument
401+
(name) => {};
402+
(on_exit) => {};
403+
(request_capabilities) => {};
404+
(grant_capabilities) => {};
405+
(public) => {};
406+
407+
// Recursively validate multiple arguments
408+
($first:ident, $($rest:ident),+ $(,)?) => {
409+
validate_spawn_args!($first);
410+
validate_spawn_args!($($rest),+);
411+
};
412+
413+
// Error case - invalid argument name
414+
($invalid:ident $(, $($rest:tt)*)?) => {
415+
compile_error!(concat!(
416+
"Invalid Spawn argument '",
417+
stringify!($invalid),
418+
"'. Valid options are: name, on_exit, request_capabilities, grant_capabilities, public"
419+
));
420+
};
421+
}

0 commit comments

Comments
 (0)