# nade
[](https://crates.io/crates/nade)
[](https://docs.rs/nade)
`nade` is a attribute macro that adds ***na***med and ***de***fault arguments to Rust functions.
## Usage
```rust
// some_crate/src/lib.rs
pub use nade::base::*;
use nade::nade;
pub fn one() -> u32 {
1
}
#[nade]
pub fn foo(
/// You can add doc comments to the parameter. It will be shown in the doc of the macro.
///
/// The world is 42.
#[nade(42)] a: u32,
/// Call a function
#[nade(one())] b: u32,
/// Default value of u32
#[nade] c: u32,
d: u32
) -> u32 {
a + b + c + d
}
assert_eq!(foo!(1, 2, 3, 4), 10); // foo(1, 2, 3, 4)
assert_eq!(foo!(d = 2), 45); // foo(42, one(), Default::default(), 2)
assert_eq!(foo!(1, c = 2, b = 3, 4), 10); // foo(1, 3, 2, 4)
```
## How it works
If you write a function like this:
```rust
// some_crate/src/lib.rs
pub use nade::base::*;
use nade::nade;
pub fn one() -> u32 {
1
}
#[nade]
pub fn foo(
#[nade(42)]
a: u32,
#[nade(one())]
b: u32,
#[nade]
c: u32,
d: u32
) -> u32 {
a + b + c + d
}
```
it will be expanded to:
```rust
// some_crate/src/lib.rs
// ⓵
pub use nade::base::*;
use nade::nade;
pub fn one() -> u32 {
1
}
pub fn foo(a: u32, b: u32, c: u32, d: u32) -> u32 {
a + b + c + d
}
// ⓶
#[::nade::__internal::macro_v(pub)]
macro_rules! foo {
($($arguments:tt)*) => {
// ⓷
$crate::nade_helper!(
($($arguments)*)
(a: u32 = 42, b: u32 = one(), c: u32 = Default::default(), d: u32)
(foo)
)
};
}
```
Then, when you call the macro `foo` like this:
```rust
use some_crate::{foo, one};
foo!(32, d = 1, c = 2);
```
it will be expanded to:
```rust
use some_crate::{foo, one};
foo(32, one(), 2, 1);
```
### Note
As you can see in [How it works](#how-it-works), there are 3 things to be aware of in the code generated by `#[nade]`.
- ⓵, ⓷
`nade_helper` is a declarative macro used to generate function call expressions based on arguments, parameters, and function path.
Its path defaults is `$crate::nade_helper`, so you need to import the macro in the root of crate using `pub use nade::base::*;` or `pub use nade::base::nade_helper;`.
Also you can customize the path of `nade_helper`.
```rust
use nade::nade;
mod custom_nade_helper {
pub use nade::base::nade_helper;
}
#[nade]
#[nade_path(nade_helper = custom_nade_helper)]
fn custom_nade_helper_path(a: usize) -> usize {
a
}
```
- ⓶
`macro_v` is an attribute macro that makes the visibility of the declarative macro the same as the function. see [macro-v](https://github.com/ZihanType/macro-v) for details.
Its path defaults is `::nade::__internal::macro_v`.
Also you can customize the path of `macro_v`.
```rust
use nade::nade;
mod custom_macro_v {
pub use nade::__internal::macro_v;
}
#[nade]
#[nade_path(macro_v = custom_macro_v)]
fn custom_macro_v_path(a: usize) -> usize {
a
}
```
## Limitations
1. When you call the macro `foo`, you must use the `use` statement to bring the macro into scope.
```rust
use some_crate::{foo, one};
foo!(32, d = 1, c = 2);
use some_crate::one;
some_crate::foo!(32, d = 1, c = 2);
```
Because the attribute macro `#[nade]` will generate a macro with the same name as the function, and the macro use the function in an unhygienic way, so you must use the `use` statement to bring the macro **and** the function into scope.
2. The default argument expression must be imported into the scope of the macro call.
```rust
use some_crate::{foo, one};
foo!(32, d = 1, c = 2);
use some_crate::foo;
foo!(32, d = 1, c = 2);
```
Because the default argument expression is evaluated after the `foo` macro is expanded, so it must be imported into the scope of the macro call.
## How to bypass the limitations
1. You can pass a module path starting with `$crate` for the `#[nade]` attribute macro on the function.
```rust
#[nade(module_path = $crate::module)] pub fn foo(
#[nade(42)]
a: u32,
#[nade(one())]
b: u32,
#[nade]
c: u32,
d: u32
) -> u32 {
a + b + c + d
}
```
it will be expanded to:
```rust
pub fn foo(a: u32, b: u32, c: u32, d: u32) -> u32 {
a + b + c + d
}
#[::nade::__internal::macro_v(pub)]
macro_rules! foo {
($($arguments:tt)*) => {
$crate::nade_helper!(
($($arguments)*)
(a: u32 = 42, b: u32 = one(), c: u32 = Default::default(), d: u32)
($crate::module::foo) )
};
}
```
Then, you can not use the `use` statement to bring the macro and the function into scope, like this:
```rust
use some_crate::one;
some_crate::foo!(32, d = 1, c = 2);
```
2. In the `#[nade]` attribute macro on the parameter, you can specify the default argument expression using the full path, either `$crate::a::expr`, or `::a::b::expr`. In fact, when you use `#[nade]` on an parameter, you are using `#[nade(::core::default::Default::default())]`.
```rust
pub fn one() -> u32 {
1
}
pub static PATH: &str = "a";
#[nade]
pub fn foo<T1, T2, T3, T4>(
#[nade($crate::module::one())]
a: T1,
#[nade(::std::path::Path::new("a"))]
b: T2,
#[nade($crate::module::PATH)]
c: T3,
#[nade("Hello")]
d: T4
) {
let _ = (a, b, c, d);
}
```
it will be expanded to:
```rust
pub fn foo<T1, T2, T3, T4>(a: T1, b: T2, c: T3, d: T4) {
let _ = (a, b, c, d);
}
#[::nade::__internal::macro_v(pub)]
macro_rules! foo {
($($arguments:tt)*) => {
$crate::nade_helper!(
($($arguments)*)
(
a: T1 = $crate::module::one(),
b: T2 = ::std::path::Path::new("a"),
c: T3 = $crate::module::PATH,
d: T4 = "Hello",
)
(foo)
)
};
}
```
Then, you can not use the `use` statement to bring default argument expressions into scope, like this:
```rust
use some_crate::foo;
foo!();
```
## Credits
This crate is inspired by these crates:
- [default-args](https://github.com/buttercrab/default-args.rs)
- [duang](https://github.com/xiaoniu-578fa6bff964d005/duang)
- [leptos](https://github.com/leptos-rs/leptos)
- [typed-builder](https://github.com/idanarye/rust-typed-builder)