#convert #arguments #optional #style #chaining #attributes #builder

无std optarg2chain

将可选参数转换为链式风格

1个不稳定版本

0.1.0 2020年2月13日

#21 in #chaining

MIT许可证

34KB
664

optarg2chain Rust

将可选参数转换为链式风格。

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_imploptarg_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

带有unsafeconstextern的函数或方法不支持。

许可证

MIT

依赖项

~1.5MB
~35K SLoC