Crates.io | fn-decorator |
lib.rs | fn-decorator |
version | 1.3.2 |
source | src |
created_at | 2023-07-05 10:10:43.757479 |
updated_at | 2024-05-27 15:41:57.026459 |
description | The crate contains macros for implementing wrapper functions around member or static functions. |
homepage | |
repository | https://github.com/RoGer2856/fn-decorator.git |
max_upload_size | |
id | 908799 |
size | 38,942 |
The crate contains macros for implementing wrapper functions around member or static functions.
use_decorator
Decorator function
fn decorator(f: fn() -> i64) -> i64 {
f() + 1
}
Decorating a function
#[use_decorator(decorator())]
fn get_1() -> i64 {
1
}
When get_1()
is called, then decorator(get_1)
is executed instead. The decorator function can decide whether it calls the received function or not.
There is also a use_impl_decorator
macro that works in impl
blocks.
Both macros can have the same parameters:
hide_parameters = [...]
: if the decorator function signature does not match the decorated, then this list can be used to hide some parameters from the decorator function. Be aware that hide_parameters
and exact_parameters
cannot be given the same time.exact_parameters = [...]
: if the decorator function signature does not match the decorated, then this list can be used to specified the exact parameters to be passed to the decorator function. Be aware that hide_parameters
and exact_parameters
cannot be given the same time.override_return_type = <type>
: if the decorator return type does not match the decorated, then this list can be used to change the return type of the decorateddebug
: when this parameter is given, then the code will generate a compile error with the generated source code. This is useful for debugging purposes.use fn_decorator::use_decorator;
fn decorator(f: fn() -> i64) -> i64 {
f() + 1
}
#[use_decorator(decorator())]
fn get_1() -> i64 {
1
}
#[test]
fn fn_without_params_decorator() {
let result = get_1();
assert_eq!(result, 2);
}
use fn_decorator::use_decorator;
fn decorator(f: fn(x: i64) -> i64, x: i64) -> i64 {
f(x) * 2
}
#[use_decorator(decorator())]
fn double(x: i64) -> i64 {
x * 2
}
#[test]
fn decorator_without_params() {
let result = double(2);
assert_eq!(result, 8);
}
use fn_decorator::use_decorator;
fn decorator(
middle: String,
f: fn(String, String) -> String,
left: String,
right: String,
) -> String {
let left = left + &middle;
f(left, right)
}
#[use_decorator(decorator("_middle_".to_string()))]
fn concat(left: String, right: String) -> String {
left + &right
}
#[test]
fn decorator_with_param() {
let result = concat("left".into(), "right".into());
assert_eq!(result, "left_middle_right");
}
Please be aware that the tests does not contain this code, because it produces a compile time error.
use fn_decorator::use_decorator;
fn decorator(f: fn() -> i64) -> i64 {
f() + 1
}
#[use_decorator(decorator(), debug)]
fn get_1() -> i64 {
1
}
#[test]
fn debug_fn_decorator() {
let result = get_1();
assert_eq!(result, 2);
}
use fn_decorator::use_impl_decorator;
fn decorator(f: fn(&MyStruct, y: i64) -> i64, receiver: &MyStruct, y: i64) -> i64 {
f(receiver, y) + 1
}
struct MyStruct {
x: i64,
}
impl MyStruct {
#[use_impl_decorator(decorator())]
fn add(&self, y: i64) -> i64 {
self.x + y
}
}
#[test]
fn impl_member_decorator() {
let obj = MyStruct { x: 1 };
let result = obj.add(1);
assert_eq!(result, 3);
}
use fn_decorator::use_impl_decorator;
fn decorator(f: fn(x: i64) -> i64, x: i64) -> i64 {
f(x) + 1
}
struct MyStruct;
impl MyStruct {
#[use_impl_decorator(decorator())]
fn double(x: i64) -> i64 {
x * 2
}
}
#[test]
fn impl_static_member_decorator() {
let result = MyStruct::double(2);
assert_eq!(result, 5);
}
use std::future::Future;
use fn_decorator::use_decorator;
async fn decorator<FutureType: Future<Output = i64>>(f: fn(x: i64) -> FutureType, x: i64) -> i64 {
f(x).await * 2
}
#[use_decorator(decorator())]
async fn double(x: i64) -> i64 {
x * 2
}
#[tokio::test]
async fn async_decorator() {
let result = double(2).await;
assert_eq!(result, 8);
}
use std::future::Future;
use fn_decorator::use_decorator;
async fn decorator<FutureType: Future<Output = String>>(
middle: String,
f: impl FnOnce(String) -> FutureType,
right: String,
) -> String {
let right = middle + &right;
f(right).await
}
#[use_decorator(decorator("_middle_".to_string()), exact_parameters = [right])]
async fn concat(left: String, right: String) -> String {
left + &right
}
#[tokio::test]
async fn hiding_params_of_async_fn_decorator() {
let result = concat("left".into(), "right".into()).await;
assert_eq!(result, "left_middle_right");
}
use std::future::Future;
use fn_decorator::use_impl_decorator;
async fn decorator<'a, FutureType: Future<Output = &'a String>>(
middle: String,
f: impl FnOnce(&'a mut MyStruct) -> FutureType,
receiver: &'a mut MyStruct,
) -> &'a String {
receiver.left.push_str(&middle);
f(receiver).await
}
struct MyStruct {
left: String,
}
impl MyStruct {
#[use_impl_decorator(decorator("_middle_".to_string()), exact_parameters = [self])]
async fn concat(&mut self, right: String) -> &String {
self.left.push_str(&right);
&self.left
}
}
#[tokio::test]
async fn hiding_params_of_async_impl_member_decorator() {
let mut obj = MyStruct {
left: "left".into(),
};
let result = obj.concat("right".into()).await;
assert_eq!(result, "left_middle_right");
}
use fn_decorator::use_decorator;
fn decorator(middle: String, f: impl FnOnce(String) -> String, right: String) -> String {
let right = middle + &right;
f(right)
}
#[use_decorator(decorator("_middle_".to_string()), exact_parameters = [right])]
fn concat(left: String, right: String) -> String {
left + &right
}
#[test]
fn hiding_params_of_fn_decorator() {
let result = concat("left".into(), "right".into());
assert_eq!(result, "left_middle_right");
}
use fn_decorator::use_impl_decorator;
fn decorator(middle: String, f: impl FnOnce(&MyStruct) -> String, receiver: &MyStruct) -> String {
let new_struct = MyStruct {
left: receiver.left.clone() + &middle,
};
f(&new_struct)
}
struct MyStruct {
left: String,
}
impl MyStruct {
#[use_impl_decorator(decorator("_middle_".to_string()), exact_parameters = [self])]
fn concat(&self, right: String) -> String {
self.left.clone() + &right
}
}
#[test]
fn hiding_params_of_impl_member_decorator() {
let obj = MyStruct {
left: "left".into(),
};
let result = obj.concat("right".into());
assert_eq!(result, "left_middle_right");
}
#[test] fn hiding_self_param_in_impl_member_decorator() { let obj = MyStruct { left: "left".into(), }; let result = obj.concat("right".into()); assert_eq!(result, "left_middle_right"); }
### Hiding parameters of an async function from a decorator
```rust
use std::future::Future;
use fn_decorator::use_decorator;
async fn decorator<FutureType: Future<Output = String>>(
middle: String,
f: impl FnOnce(String) -> FutureType,
right: String,
) -> String {
let right = middle + &right;
f(right).await
}
#[use_decorator(decorator("_middle_".to_string()), hide_parameters = [left])]
async fn concat(left: String, right: String) -> String {
left + &right
}
#[tokio::test]
async fn hiding_params_of_async_fn_decorator() {
let result = concat("left".into(), "right".into()).await;
assert_eq!(result, "left_middle_right");
}
use std::future::Future;
use fn_decorator::use_impl_decorator;
async fn decorator<'a, FutureType: Future<Output = &'a String>>(
middle: String,
f: impl FnOnce(&'a mut MyStruct) -> FutureType,
receiver: &'a mut MyStruct,
) -> &'a String {
receiver.left.push_str(&middle);
f(receiver).await
}
struct MyStruct {
left: String,
}
impl MyStruct {
#[use_impl_decorator(decorator("_middle_".to_string()), hide_parameters = [right])]
async fn concat(&mut self, right: String) -> &String {
self.left.push_str(&right);
&self.left
}
}
#[tokio::test]
async fn hiding_params_of_async_impl_member_decorator() {
let mut obj = MyStruct {
left: "left".into(),
};
let result = obj.concat("right".into()).await;
assert_eq!(result, "left_middle_right");
}
use fn_decorator::use_decorator;
fn decorator(middle: String, f: impl FnOnce(String) -> String, right: String) -> String {
let right = middle + &right;
f(right)
}
#[use_decorator(decorator("_middle_".to_string()), hide_parameters = [left])]
fn concat(left: String, right: String) -> String {
left + &right
}
#[test]
fn hiding_params_of_fn_decorator() {
let result = concat("left".into(), "right".into());
assert_eq!(result, "left_middle_right");
}
use fn_decorator::use_impl_decorator;
fn decorator(middle: String, f: impl FnOnce(&MyStruct) -> String, receiver: &MyStruct) -> String {
let new_struct = MyStruct {
left: receiver.left.clone() + &middle,
};
f(&new_struct)
}
struct MyStruct {
left: String,
}
impl MyStruct {
#[use_impl_decorator(decorator("_middle_".to_string()), hide_parameters = [right])]
fn concat(&self, right: String) -> String {
self.left.clone() + &right
}
}
#[test]
fn hiding_params_of_impl_member_decorator() {
let obj = MyStruct {
left: "left".into(),
};
let result = obj.concat("right".into());
assert_eq!(result, "left_middle_right");
}
use fn_decorator::use_impl_decorator;
fn decorator(middle: String, f: impl FnOnce(String) -> String, right: String) -> String {
let right = middle + &right;
f(right)
}
struct MyStruct {
left: String,
}
impl MyStruct {
#[use_impl_decorator(decorator("_middle_".to_string()), hide_parameters = [self])]
fn concat(&self, right: String) -> String {
self.left.clone() + &right
}
}
#[test]
fn hiding_self_param_in_impl_member_decorator() {
let obj = MyStruct {
left: "left".into(),
};
let result = obj.concat("right".into());
assert_eq!(result, "left_middle_right");
}
use std::future::Future;
use fn_decorator::use_impl_decorator;
async fn decorator<'a, FutureType: Future<Output = i64>>(
f: fn(&'a MyStruct, y: i64) -> FutureType,
receiver: &'a MyStruct,
y: i64,
) -> i64 {
f(receiver, y).await + 1
}
struct MyStruct {
x: i64,
}
impl MyStruct {
#[use_impl_decorator(decorator())]
async fn add(&self, y: i64) -> i64 {
self.x + y
}
}
#[tokio::test]
async fn async_impl_member_decorator() {
let obj = MyStruct { x: 1 };
let result = obj.add(1).await;
assert_eq!(result, 3);
}
use std::future::Future;
use fn_decorator::use_impl_decorator;
async fn decorator<FutureType: Future<Output = i64>>(f: fn(y: i64) -> FutureType, x: i64) -> i64 {
f(x).await + 1
}
struct MyStruct;
impl MyStruct {
#[use_impl_decorator(decorator())]
async fn double(x: i64) -> i64 {
x * 2
}
}
#[tokio::test]
async fn async_impl_member_decorator() {
let result = MyStruct::double(2).await;
assert_eq!(result, 5);
}
use fn_decorator::use_decorator;
fn decorator(f: fn() -> i64) -> Result<i64, ()> {
Ok(f() + 1)
}
#[use_decorator(decorator(), override_return_type = Result<i64, ()>)]
fn get_1() -> i64 {
1
}
#[use_decorator(decorator(), override_return_type = impl ::std::any::Any)]
fn get_2() -> i64 {
2
}
#[test]
fn overriding_return_type() {
let result = get_1();
assert_eq!(result, Ok(2));
let result = get_2();
assert_eq!("core::result::Result<i64, ()>", ::std::any::type_name_of_val(&result));
}