@@ -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