Python-style function decorators for Rust
Example usage:
use adorn::{adorn, make_decorator};
#[adorn(bar)]
fn foo(a: &mut u8, b: &mut u8, (c, _): (u8, u8)) {
assert!(c == 4);
*a = c;
*b = c;
}
fn bar<F>(f: F, a: &mut u8, b: &mut u8, (c, d): (u8, u8)) where F: Fn(&mut u8, &mut u8, (u8, u8)) {
assert!(c == 0 && d == 0);
f(a, b, (4, 0));
*b = 100;
}
fn main() {
let mut x = 0;
let mut y = 1;
foo(&mut x, &mut y, (0, 0));
assert!(x == 4 && y == 100);
}
In this case, foo
will become:
fn foo(a: &mut u8, b: &mut u8, (c, d): (u8, u8)) {
fn foo_inner(a: &mut u8, b: &mut u8, (c, _): (u8, u8)) {
assert!(c == 4);
*a = c;
*b = c;
}
bar(foo_inner, a, b, (c, d))
}
In other words, calling foo()
will actually call bar()
wrapped around foo()
.
There is a #[make_decorator]
attribute to act as sugar for creating decorators. For example,
#[make_decorator(f)]
fn bar(a: &mut u8, b: &mut u8, (c, d): (u8, u8)) {
assert!(c == 0 && d == 0);
f(a, b, (4, 0)); // `f` was declared in the `make_decorator` annotation
*b = 100;
}
desugars to
fn bar<F>(f: F, a: &mut u8, b: &mut u8, (c, d): (u8, u8)) where F: Fn(&mut u8, &mut u8, (u8, u8)) {
assert!(c == 0 && d == 0);
f(a, b, (4, 0));
*b = 100;
}
Example usage:
use adorn::{adorn_method, make_decorator_method};
pub struct Test {
a: u8,
b: u8
}
impl Test {
#[adorn_method(bar)]
fn foo(&mut self, a: u8, b: u8) {
assert!(a == 0 && b == 0);
self.a = a;
self.b = b;
}
fn bar<F>(&mut self, f: F, a: u8, b: u8) where F: Fn(Self, u8, u8) {
assert!(a == 0 && b == 0);
f(self, a, b);
self.b = 100;
}
}
fn main() {
let mut t = Test {
a: 1,
b: 1,
};
t.foo(0, 0);
assert!(t.a == 0 && t.b == 100);
}
In this case, foo
will become:
impl Test {
fn foo(&mut self, a: u8, b: u8) {
let foo_inner = |s: &mut Self, a: u8, b: u8| {
assert!(a == 0 && b == 0);
s.a = a;
s.b = b;
};
self.bar(foo_inner, a, b, (c, d))
}
}
Similarly, a #[make_decorator_method]
attribute is provided to create decorators. For example,
impl Test {
#[make_decorator_method(f)]
fn bar(&mut self, a: u8, b: u8) {
assert!(a == 0 && b == 0);
f(self, a, b); // `f` was declared in the `make_decorator_method` annotation
self.b = 100;
}
}
desugars to
impl Test{
fn bar<F>(&mut self, f: F, a: u8, b: u8) where F: Fn(Self, u8, u8) {
assert!(a == 0 && b == 0);
f(self, a, b);
self.b = 100;
}
}
Use #[make_decorator_static]
and #[adorn_static]
to make a static decorator and then use it to decorate a static method, for example
use adorn::{adorn_method, make_decorator_method};
pub struct Test {
a: u8,
b: u8
}
impl Test {
#[adorn_static(bar)]
fn foo(a: u8, b: u8) -> Self {
assert!(a == 0 && b == 0);
Self {
a,
b
}
}
#[make_decorator_static(f)]
fn bar(a: u8, b: u8) -> Self {
assert!(a == 0 && b == 0);
let mut retval = f(a, b);
retval.b = 100;
retval
}
}
fn main() {
let t = Test::foo(0, 0);
assert!(t.a == 0 && t.b == 100);
}
The two static methods desugar to
impl Test {
fn foo(a: u8, b: u8) -> Self {
let foo_inner = |a: u8, b: u8| -> Self {
assert!(a == 0 && b == 0);
Self {
a,
b
}
};
Self::bar(foo, a, b)
}
fn bar(f: F, a: u8, b: u8) -> Self where F: Fn(u8, u8) -> Self {
assert!(a == 0 && b == 0);
let mut retval = f(a, b);
retval.b = 100;
retval
}
}