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 模式
40KB
419 行
fluent-impl
Linux | OSX | Windows |
---|---|---|
一个过程宏,可以将 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]
不同,此属性
- 适用于方法而不是实现块。
- 如果您愿意,可以多次传递给同一方法。
示例
#[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
不允许设置,如果方法特定的prefix
或rename
已设置。
完整示例
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