#impl-block #chaining #attributes #fluent #proc-macro #api

fluent-impl

一个过程宏,可以将 impl 块中的非链式方法生成链式方法

5 个版本

使用旧的 Rust 2015

0.2.0 2018 年 10 月 30 日
0.1.4 2018 年 8 月 17 日
0.1.3 2018 年 8 月 14 日
0.1.2 2018 年 8 月 14 日
0.1.1 2018 年 8 月 14 日

#2311 in Rust 模式

MPL-2.0 许可证

40KB
419

fluent-impl 包 文档 Travis 构建状态 AppVeyor 构建状态 最小 Rust 版本:1.30

Linux OSX Windows
linux-nightly osx-nightly windows-nightly
linux-beta osx-beta windows-beta
linux-stable osx-stable windows-stable

一个过程宏,可以将 impl 块中的非链式方法生成链式方法。

当应用于 impl 块时,#[fluent_impl] 将扫描块中的所有方法,以寻找可链式方法,并从它们生成链式方法。

可链式方法是那些以 &mut self 作为第一个参数,并返回空值的方法。就是这样,没有其他限制。

用法

fluent-impl 添加到 Cargo.toml 中的依赖项。然后添加以下内容到 src/lib.rs 的顶部

extern crate fluent_impl;

use fluent_impl::{fluent_impl, fluent_impl_opts};

示例

如果我们有一个简单的结构体和一个简单的 impl 块

#[derive(Default, PartialEq, Debug)]
pub struct Simple {
    num: i32,
}

impl Simple {
    // ...
    pub fn add_1(&mut self) {
        self.num +=1;
    }
}

然后我们将宏属性添加到 impl 块中

#[fluent_impl]
impl Simple {
    // ...
    pub fn add_1(&mut self) {
        self.num +=1;
    }
}

该宏将生成一个新的 impl 块,其内容为

#[doc = "Chaining (fluent) methods for [`Simple`]."]
impl Simple {
    #[doc = "The chaining (fluent) equivalent of [`add_1()`].\n\n [`add_1`]: Simple::add_1\n [`add_1()`]: Simple::add_1"]
    pub fn with_add_1(mut self) -> Self {
        self.add_1();
        self
    }
}

一个更完整的示例可以在 属性配置 部分的下方找到。

属性配置

#[fluent_impl] 可以通过传递给属性的逗号分隔的选项进行配置,以及传递给方法级别属性 #[fluent_impl_opts] 的选项进行配置。

#[fluent_impl] 属性选项

(inblock, non_public, prefix, impl_doc, doc)

实现块级别配置。

示例

#[fluent_impl(inblock, non_public, prefix="chain_")]
impl Simple {
    // ...
}

选项

  • inblock (默认:未设置)

    默认情况下,将生成一个新的实现块,并在此处添加链式方法。如果传递了inblock,则每个链式方法将直接生成在可链式方法下方。

    方法在文档中出现的顺序可能是您应该关注的唯一原因。

    存在一个对应的方法级inblock选项,将选择性地为单个方法启用此行为。

  • non_public (默认:未设置)

    默认情况下,跳过非完全公开的方法。如果传递此选项,宏将生成链式等效的私有或部分公开的方法。

    存在一个对应的方法级non_public选项,将选择性地为单个方法启用此行为。

  • prefix (默认: "with_")

    默认链式方法名称是以此前缀附加的可链式方法名称。

    • prefix不允许为空字符串。如果您想将链式方法命名为您喜欢的任何名称,请检查name方法级选项。

    存在一个对应的方法级prefix选项,将选择性地覆盖此处设置的值(或默认值)。

  • impl_doc (默认: "为[`%t%`]提供链式(流畅)方法。")

    如果为链式方法生成新块,这是该块的文档字符串模板。%t%将被类型路径替换。

  • doc (默认: "将[`%f%()`]的链式(流畅)等效。")

    链式方法文档字符串模板。%t%将被类型路径替换。%f%将被可链式方法名称替换。

    此外,以下内容实际上附加在末尾

     ///
     /// [`%f%`]: %t%::%f%
     /// [`%f%()`]: %t%::%f%
    

    这允许正确链接[`%t%`][`%t%()`]

    存在一个对应的方法级doc选项,将选择性地覆盖此处设置的值(或默认值)。

#[fluent_impl_opts] 属性选项

(inblock, non_public, skip, prefix, rename, name, doc)

传递给覆盖块级默认值或设置方法特定配置的选项。

#[fluent_impl]不同,此属性

  1. 适用于方法而不是实现块。
  2. 如果您愿意,可以多次传递给同一方法。

示例

#[fluent_impl]
impl Simple {
    #[fluent_impl_opts(non_public, inblock)]
    #[fluent_impl_opts(prefix="chain_", rename="added_1")]
    fn add_1(&mut self) {
        // ...
    }
}

选项

继承

  • inblock (默认:继承)

    如果块尚未设置inblock,则为此特定方法设置inblock

  • non_public (默认:继承)

    如果块尚未设置non_public,则为此特定方法设置non_public

    这允许为特定的私有方法或部分公开的方法(例如 pub(crate) 方法)生成链式方法。

  • prefix(默认:继承)

    覆盖默认值或已设置的块值。

    • prefix不允许为空字符串。
    • 如果设置了name(见下文),则不允许设置方法特定的prefix
  • doc(默认:继承)

    覆盖默认值或已设置的块值。

方法特定

  • skip(默认:未设置)

    跳过此方法。不要从中生成任何内容。

  • rename(默认:可链式名称)

    默认链式方法名称是附加到可链式方法名称的前缀。此选项允许您重命名要添加到前缀的名称。

    • rename不允许为空字符串。
    • rename不允许设置,如果name(见下文)已设置,反之亦然。
  • name(默认:未设置)

    设置链式方法名称。

    • name不允许设置,如果方法特定的prefixrename已设置。

完整示例

extern crate fluent_impl;

pub mod m {
    use fluent_impl::{fluent_impl, fluent_impl_opts};
    use std::borrow::Borrow;
    use std::ops::AddAssign;

    #[derive(PartialEq, Debug)]
    pub struct TCounter(pub u32);

    #[derive(PartialEq, Debug)]
    pub struct St<A: AddAssign> {
        value: A,
        text: String,
    }

    #[fluent_impl]
    // impl block with generic arguments works
    impl<A: AddAssign> St<A> {
        // Constants (or any other items) in impl block are okay
        pub(crate) const C_TC: u32 = 100;

        pub fn new(value: A, text: String) -> Self {
            Self { value, text }
        }

        pub fn get_value(&self) -> &A {
            &self.value
        }

        pub fn get_text(&self) -> &str {
            &self.text
        }

        #[fluent_impl_opts(rename = "added_value")]
        // Destructuring patterns in method arguments are okay
        pub fn add_value(
            &mut self,
            to_be_added: A,
            TCounter(counter): &mut TCounter,
        ) {
            self.value += to_be_added;
            *counter += 1;
        }

        #[fluent_impl_opts(rename = "appended_text")]
        // Generic method arguments are okay
        pub fn append_text<S: Borrow<str>>(&mut self, arg: S) {
            self.text += arg.borrow();
        }

        #[fluent_impl_opts(rename = "appended_text_impl_trait")]
        // Needless to say, impl Trait method arguments are also okay
        pub fn append_text_impl_trait(&mut self, arg: impl Borrow<str>) {
            self.text += arg.borrow();
        }
    }
}

fn main() {
    use m::{St, TCounter};
    // ========
    let mut tc1 = TCounter(St::<u32>::C_TC);
    let mut s1 = St::new(0u32, "".into());
    s1.append_text("simple ");
    s1.append_text::<&str>("turbo fish ");
    s1.append_text_impl_trait("impl trait");
    s1.add_value(5, &mut tc1);
    assert_eq!(s1.get_text(), "simple turbo fish impl trait");
    assert_eq!(tc1, TCounter(St::<u32>::C_TC + 1));
    // ========
    let mut tc2 = TCounter(St::<u32>::C_TC);
    let s2 = St::new(0u32, "".into())
        .with_appended_text("simple ")
        .with_appended_text::<&str>("turbo fish ")
        .with_appended_text_impl_trait("impl trait")
        .with_added_value(5, &mut tc2);
    assert_eq!(s2, s1);
    assert_eq!(tc2, tc1);
}

依赖关系

~2MB
~46K SLoC