Attribute Macro wrap

Source
#[wrap]
Expand description

Procedural macro that will decorate the incoming function with the provided context.

The context is expected to be a type that implements the SyncWrapContext trait.

Usage example:

struct PrintDuration;
impl<T> context_manager::SyncWrapContext<T> for PrintDuration {
  fn new() -> Self { Self }
}

#[wrap(PrintDuration)]
fn sync_foo<'a, T>(int_value: usize, str_ref: &'a str, generic: T) -> usize {
    let type_name = std::any::type_name::<T>();
    println!("Sync call with int_value={int_value}, str_ref={str_ref}, type_of(T)={type_name}");
    10
}

#[wrap(PrintDuration)]
async fn async_foo<'a, T>(int_value: usize, str_ref: &'a str, generic: T) -> usize {
    let type_name = std::any::type_name::<T>();
    println!("Async call with int_value={int_value}, str_ref={str_ref}, type_of(T)={type_name}");
    10
}

The decorator does not induce limits on the shape of the incoming function, in terms of generics, sync/async, lifetime, etc.

The decorator will expand the incoming function by adding the context handling rendering something similar to

fn sync_foo<'a, T>(int_value: usize, str_ref: &'a str, generic: T) -> usize {
    PrintDuration::run_sync(CallerContext { fn_name: "sync_foo" }, move || {
        let type_name = std::any::type_name::<T>();
        println!("Sync call with int_value={int_value}, str_ref={str_ref}, type_of(T)={type_name}");
        10
    })
}

async fn async_foo<'a, T>(int_value: usize, str_ref: &'a str, generic: T) -> usize {
    PrintDuration::run_async(CallerContext { fn_name: "async_foo" }, async {
        let type_name = std::any::type_name::<T>();
        println!("Async call with int_value={int_value}, str_ref={str_ref}, type_of(T)={type_name}");
        10
    }).await
}

The structuring of the generated code is though to avoid any clone/copy of data, as well as reducing the number of jumps needed to execute the original code.

§Possible compile errors

§Passing a type that does not implement SyncWrapContext trait will lead to compile errors.

struct AsyncPrintDuration;
impl<T> context_manager::AsyncWrapContext<T> for AsyncPrintDuration {
  async fn new() -> Self { Self }
}

#[wrap(AsyncPrintDuration)]
fn foo() {}

would lead to the following compile error

---- src/lib.rs - decorate (line 98) stdout ----
error[E0277]: the trait bound `AsyncPrintDuration: SyncWrapContext<_>` is not satisfied
  --> src/lib.rs:106:12
   |
11 | #[wrap(AsyncPrintDuration)]
   |            ^^^^^^^^^^^^^^^^^^ the trait `SyncWrapContext<_>` is not implemented for `AsyncPrintDuration`
   |
   = help: the trait `SyncWrapContext<T>` is implemented for `TraceDuration`

§Decorating a constant function

Const functions are not supported for decoration. This is a side-effect of embedding code that is not const compatible (like async blocks and closures).

struct PrintDuration;
impl<T> context_manager::SyncWrapContext<T> for PrintDuration {
  fn new() -> Self { Self }
}

#[wrap(PrintDuration)]
const fn foo() {}

would lead to the following error

error: #[wrap] cannot operate on const functions
  --> context_manager_macro/src/lib.rs:131:1
   |
11 | #[wrap(PrintDuration)]
   | ^^^^^^^^^^^^^^^^^^^^^^
   |

Procedural macro that will decorate the incoming function with the provided context.

The context is expected to be a type that implements the context_manager::SyncWrapContext trait.

More documentation available here