1个不稳定版本
0.1.0 | 2020年2月13日 |
---|
#21 in #chaining
34KB
664 行
optarg2chain
将可选参数转换为链式风格。
Rust没有可选或命名参数。该crate提供宏将属性提供的可选参数转换为方法链式风格。
示例
函数
use optarg2chain::optarg_fn;
// specify optarg_fn attribute with builder struct name and terminal method name
#[optarg_fn(JoinStringBuilder, exec)]
fn join_strings(
mut a: String, // Required argument, no default value
#[optarg_default] b: String, // String::default() is the default value to b
#[optarg("ccc".to_owned())] c: String, // "ccc".to_owned() is the default value to c
) -> String {
a.push_str(&b);
a.push_str(&c);
a
}
此代码展开如下
struct JoinStringBuilder {
a: String,
b: core::option::Option<String>,
c: core::option::Option<String>,
_optarg_marker: core::marker::PhantomData<fn() -> ()>,
}
impl JoinStringBuilder {
fn b<_OPTARG_VALUE: core::convert::Into<String>>(mut self, value: _OPTARG_VALUE) -> Self {
let value = <_OPTARG_VALUE as core::convert::Into<String>>::into(value);
self.b = Some(value);
self
}
fn c<_OPTARG_VALUE: core::convert::Into<String>>(mut self, value: _OPTARG_VALUE) -> Self {
let value = <_OPTARG_VALUE as core::convert::Into<String>>::into(value);
self.c = Some(value);
self
}
fn exec(self) -> String {
fn _optarg_inner_func(mut a: String, b: String, c: String) -> String {
a.push_str(&b);
a.push_str(&c);
a
}
let a: String = self.a;
let b: String = self
.b
.unwrap_or_else(|| <String as core::default::Default>::default());
let c: String = self.c.unwrap_or_else(|| "ccc".to_owned());
_optarg_inner_func(a, b, c)
}
}
fn join_strings(a: String) -> JoinStringBuilder {
JoinStringBuilder {
a,
b: core::option::Option::None,
c: core::option::Option::None,
_optarg_marker: core::marker::PhantomData,
}
}
optarg_fn
生成构建器结构体、可选参数设置器和终端方法。您可以使用上面的join_strings
如下所示
assert_eq!(join_strings("aaa".to_owned()).exec(), "aaaccc");
assert_eq!(
join_strings("xxx".to_owned())
.b("yyy".to_owned())
.c("zzz".to_owned())
.exec(),
"xxxyyyzzz"
);
方法
optarg_impl
和optarg_method
属性是为方法准备的。
use optarg2chain::optarg_impl;
struct MyVec<T> {
data: Vec<T>,
}
#[optarg_impl]
impl<T: Default + Copy> MyVec<T> {
#[optarg_method(MyVecGetOr, get)]
fn get_or<'a>(&'a self, i: usize, #[optarg_default] other: T) -> T { // Lifetimes need to be given explicitly
self.data.get(i).copied().unwrap_or(other)
}
}
您可以使用以下方式使用它
let myvec = MyVec { data: vec![2, 4, 6] };
assert_eq!(myvec.get_or(1).get(), 4);
assert_eq!(myvec.get_or(10).get(), 0);
assert_eq!(myvec.get_or(10).other(42).get(), 42);
实现特性
#[optarg_fn(GenIter, iter)]
fn gen_iter<T: Default>(
#[optarg_default] a: T,
#[optarg_default] b: T,
#[optarg_default] c: T,
) -> impl Iterator<Item = T> {
vec![a, b, c].into_iter()
}
let iter = gen_iter::<i32>().iter();
assert_eq!(iter.collect::<Vec<i32>>(), vec![0, 0, 0]);
let iter = gen_iter::<i32>().a(1).b(2).c(3).iter();
assert_eq!(iter.collect::<Vec<i32>>(), vec![1, 2, 3]);
限制
在参数类型中需要显式给出引用
正确
#[optarg_impl]
impl Foo {
#[optarg_method(DoSomething, exec)]
fn do_something<'a, 'b>(&'a self, s: &'b str, ...) { ... }
}
不正确
#[optarg_impl]
impl Foo {
#[optarg_method(DoSomething, exec)]
fn do_something(&self, s: &str, ...) { ... }
}
不支持参数位置中的impl特性
显式类型泛型是参数位置中impl特性的替代。
正确
#[optarg_fn(PrintWith, exec)]
fn print_with<'b, T: std::fmt::Display>(a: T, #[optarg_default] b: &'b str) {
println!("{}\n{}", a, b);
}
不正确
#[optarg_fn(PrintWith, exec)]
fn print_with<'b>(a: impl std::fmt::Display, #[optarg_default] b: &'b str) {
println!("{}\n{}", a, b);
}
参数模式
如(a, b): (i32, i8)
或Foo { x }: Foo
在参数位置是不允许的。
extern, const, unsafe
带有unsafe
、const
或extern
的函数或方法不支持。
许可证
MIT
依赖项
~1.5MB
~35K SLoC