2 releases
0.0.2 | May 1, 2020 |
---|---|
0.0.1 | May 1, 2020 |
#650 in Procedural macros
8KB
105 lines
TCO
TCO is a tail-call optimization library. It's a proof-of-concept attribute macro you can slap onto item functions to optimize them if they are in tail-calling format.
Limitations
It's not very smart.
It doesn't actually verify the function is a tail calling function.
It only works on free functions (eg. fn foo(bar: Bar) -> u32
not in an impl block).
It can have problems with passing a non-copy argument.
It's untested with references.
It doesn't support mutual recursion.
It supports only basic patterns in the function argument (no tuple destructuring).
It can't turn a non-tail calling into a tail calling function.
Help wanted
This is just a proof-of-concept. I'd love help fleshing it out.
Alternatives
- (tramp)https://docs.rs/tramp/0.3.0/tramp/
- (async-recursion)https://docs.rs/async-recursion/0.3.1/async_recursion/
Examples
Enough talk, examples!
Sync Example: Factorial
#[tco::rewrite]
fn fac_with_acc(n: u128, acc: u128) -> u128 {
if n > 1 {
fac_with_acc(n - 1, acc * n)
} else {
acc
}
}
expands to
fn fac_with_acc(n: u128, acc: u128) -> u128 {
let mut n = n;
let mut acc = acc;
'__tco_loop: loop {
return {
if n > 1 {
{
let __tco_0 = (n - 1, acc * n);
n = __tco_0.0;
acc = __tco_0.1;
continue '__tco_loop;
}
} else {
acc
}
};
}
}
Async Example: Factorial
#[tco::rewrite]
async fn fac_with_acc(n: u128, acc: u128) -> u128 {
if n > 1 {
fac_with_acc(n - 1, acc * n).await
} else {
acc
}
}
expands to
async fn fac_with_acc(n: u128, acc: u128) -> u128 {
let mut n = n;
let mut acc = acc;
'__tco_loop: loop {
return {
if n > 1 {
{
let __tco_0 = (n - 1, acc * n);
n = __tco_0.0;
acc = __tco_0.1;
continue '__tco_loop;
}
} else {
acc
}
};
}
}
without the tco::rewrite attribute, you instead get the folliwing error:
error[E0733]: recursion in an `async fn` requires boxing
--> $DIR/await_no_tco.rs:6:46
|
6 | async fn fac_with_acc(n: u128, acc: u128) -> u128 {
| ^^^^ recursive `async fn`
|
= note: a recursive `async fn` must be rewritten to return a boxed `dyn Future`
Dependencies
~1.5MB
~36K SLoC