Crates.io | nade |
lib.rs | nade |
version | 0.3.3 |
source | src |
created_at | 2023-03-18 17:21:51.054034 |
updated_at | 2023-10-12 09:10:59.279839 |
description | Adding named and default arguments to Rust functions |
homepage | https://github.com/ZihanType/nade |
repository | https://github.com/ZihanType/nade |
max_upload_size | |
id | 813862 |
size | 9,731 |
English | 简体中文
nade
is a attribute macro that adds named and default arguments to Rust functions.
// 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)
If you write a function like this:
// 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:
// 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:
use some_crate::{foo, one};
foo!(32, d = 1, c = 2);
it will be expanded to:
use some_crate::{foo, one};
foo(32, one(), 2, 1);
As you can see in 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
.
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 for details.
Its path defaults is ::nade::__internal::macro_v
.
Also you can customize the path of macro_v
.
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
}
When you call the macro foo
, you must use the use
statement to bring the macro into scope.
// Good
use some_crate::{foo, one};
foo!(32, d = 1, c = 2);
// Bad
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.
The default argument expression must be imported into the scope of the macro call.
// Good
use some_crate::{foo, one};
foo!(32, d = 1, c = 2);
// Bad
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.
You can pass a module path starting with $crate
for the #[nade]
attribute macro on the function.
#[nade(module_path = $crate::module)] // <--- here
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:
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) // <--- here
)
};
}
Then, you can not use the use
statement to bring the macro and the function into scope, like this:
use some_crate::one;
some_crate::foo!(32, d = 1, c = 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())]
.
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:
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:
use some_crate::foo;
foo!();
This crate is inspired by these crates: