9 个版本
0.4.0-alpha.0 | 2021 年 5 月 9 日 |
---|---|
0.3.3 | 2020 年 9 月 24 日 |
0.3.2 | 2020 年 7 月 8 日 |
0.3.1 | 2020 年 2 月 11 日 |
0.2.1 | 2019 年 6 月 1 日 |
#184 在 过程宏
672 每月下载量
用于 32 个 crates (10 个直接使用)
61KB
1.5K SLoC
Rust-Property
自动生成结构体的一些常用方法。
用法
将 derive proc-macro #[derive(Property)]
应用到结构体上,并使用 #[property(..)]
来配置它。
属性有三个级别
-
设置 crate 属性可以更改整个 crate 中所有容器(结构体)的默认设置。
受过程宏限制,这里我们不得不使用一种巧妙的方法来设置 crate 属性
#[property_default(get(..), set(..), ..)] struct PropertyCrateConf; // This struct is only used for introducing the attribute macro, and it will be removed in the macro.
-
设置容器属性可以更改容器中所有字段的默认属性。
-
通过设置字段属性来更改单个字段的设置。
如果没有设置属性,则将应用默认属性
#[property(
get(crate, prefix = "", suffix = "", type="auto"),
set(crate, prefix = "set_", type = "ref"),
mut(crate, prefix = "mut_"),
clr(crate, prefix = "clear_", scope = "option")
ord(asc)
)]
有六种可配置的属性:skip
、get
、set
、mut
、clr
和 ord
。
-
如果设置了
skip
属性,则不会生成任何方法。 -
方法的可视性可以通过以下方式设置:
#[property(get(visibility-type))]
存在四种可见性类型:
disable
、public
、crate
(所有方法的默认值)和private
。 -
方法名可以通过两种方式设置
-
通过以下方式分配完整的名称:
#[property(get(name = "method-name"))]
。 -
通过以下方式设置
prefix
和/或suffix
:#[property(set(prefix = "set_"), mut(suffix = "mut_"))]
。
所有字段的默认设置如下:
#[property(get(prefix = "", suffix = ""), set(prefix = "set_"), mut(prefix = "mut_"))]
。 -
-
get
方法的返回类型可以通过以下方式设置:#[property(get(type = "return-type"))]
。返回类型有四种:
auto
(默认),ref
,clone
和copy
。 -
set
方法的输入类型和返回类型可以通过以下方式设置:#[property(set(type = "set-type"))]
。输入类型有四种:
ref
(默认),own
,none
和replace
-
ref
:输入是一个可变引用,返回值也是可变引用。 -
own
:输入是一个拥有对象,返回值也是拥有对象。 -
none
:输入是一个可变引用,没有返回值。 -
replace
:输入是一个可变引用,返回旧值。
-
-
set
方法还有一个额外的属性full_option
:如果值是Option<T>
,则默认参数是T
,无需此属性。
-
clr
方法将字段设置为其默认值。它有一个scope
属性-
auto
:将为某些预设类型生成clr
方法,例如Vec
,Option
等。 -
option
:(默认)只为Option
生成clr
方法。 -
all
:将为所有类型生成clr
方法。
-
-
如果有一个字段具有多个
ord
属性,将自动实现PartialEq
和PartialOrd
。-
ord
字段属性需要一个序列号,它是一个带_
前缀的无符号数。序列号可以是断续的,但任意两个数字不能相等。
如果
ord
属性是容器属性,则不允许序列号。 -
有两种排序类型:
asc
和desc
。默认为升序(
asc
),如果设置了desc
,则可以更改为降序。
-
操作示例
原始代码
#![no_std]
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std as alloc;
use alloc::{string::String, vec::Vec};
use property::{property_default, Property};
#[property_default(get(public), ord(desc), clr(scope = "option"))]
struct PropertyCrateConf;
#[derive(Copy, Clone)]
pub enum Species {
Dog,
Cat,
Bird,
Other,
}
#[derive(Property)]
#[property(set(private), mut(disable))]
pub struct Pet {
#[property(get(name = "identification"), set(disable), ord(asc, _2))]
id: [u8; 32],
name: String,
#[property(set(crate, type = "own"), ord(_0))]
age: u32,
#[property(get(type = "copy"))]
species: Species,
#[property(get(prefix = "is_"), ord(_1))]
died: bool,
#[property(get(type = "clone"), set(type = "none"))]
owner: String,
#[property(clr(scope = "auto"))]
family_members: Vec<String>,
#[property(get(type = "ref"), mut(crate))]
info: String,
#[property(get(disable), set(type = "replace"))]
pub tag: Vec<String>,
#[property(mut(public, suffix = "_mut"))]
note: Option<String>,
#[property(set(type = "replace", full_option))]
price: Option<u32>,
#[property(skip)]
pub reserved: String,
}
生成代码
impl Pet {
#[inline]
pub fn identification(&self) -> &[u8] {
&self.id[..]
}
#[inline]
pub fn name(&self) -> &str {
&self.name[..]
}
#[inline]
fn set_name<T: Into<String>>(&mut self, val: T) -> &mut Self {
self.name = val.into();
self
}
#[inline]
pub fn age(&self) -> u32 {
self.age
}
#[inline]
pub(crate) fn set_age<T: Into<u32>>(mut self, val: T) -> Self {
self.age = val.into();
self
}
#[inline]
pub fn species(&self) -> Species {
self.species
}
#[inline]
fn set_species<T: Into<Species>>(&mut self, val: T) -> &mut Self {
self.species = val.into();
self
}
#[inline]
pub fn is_died(&self) -> bool {
self.died
}
#[inline]
fn set_died<T: Into<bool>>(&mut self, val: T) -> &mut Self {
self.died = val.into();
self
}
#[inline]
pub fn owner(&self) -> String {
self.owner.clone()
}
#[inline]
fn set_owner<T: Into<String>>(&mut self, val: T) {
self.owner = val.into();
}
#[inline]
pub fn family_members(&self) -> &[String] {
&self.family_members[..]
}
#[inline]
fn set_family_members<T: Into<String>>(
&mut self,
val: impl IntoIterator<Item = T>,
) -> &mut Self {
self.family_members = val.into_iter().map(Into::into).collect();
self
}
#[inline]
pub(crate) fn clear_family_members(&mut self) {
self.family_members.clear();
}
#[inline]
pub fn info(&self) -> &String {
&self.info
}
#[inline]
fn set_info<T: Into<String>>(&mut self, val: T) -> &mut Self {
self.info = val.into();
self
}
#[inline]
pub(crate) fn mut_info(&mut self) -> &mut String {
&mut self.info
}
#[inline]
fn set_tag<T: Into<String>>(&mut self, val: impl IntoIterator<Item = T>) -> Vec<String> {
::core::mem::replace(&mut self.tag, val.into_iter().map(Into::into).collect())
}
#[inline]
pub fn note(&self) -> Option<&String> {
self.note.as_ref()
}
#[inline]
fn set_note<T: Into<String>>(&mut self, val: T) -> &mut Self {
self.note = Some(val.into());
self
}
#[inline]
pub fn note_mut(&mut self) -> &mut Option<String> {
&mut self.note
}
#[inline]
pub(crate) fn clear_note(&mut self) {
self.note = None;
}
#[inline]
pub fn price(&self) -> Option<u32> {
self.price
}
#[inline]
fn set_price<T: Into<Option<u32>>>(&mut self, val: T) -> Option<u32> {
::core::mem::replace(&mut self.price, val.into())
}
#[inline]
pub(crate) fn clear_price(&mut self) {
self.price = None;
}
}
impl PartialEq for Pet {
fn eq(&self, other: &Self) -> bool {
self.age == other.age && self.died == other.died && self.id == other.id
}
}
impl PartialOrd for Pet {
fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
let result = other.age.partial_cmp(&self.age);
if result != Some(::core::cmp::Ordering::Equal) {
return result;
}
let result = other.died.partial_cmp(&self.died);
if result != Some(::core::cmp::Ordering::Equal) {
return result;
}
let result = self.id.partial_cmp(&other.id);
if result != Some(::core::cmp::Ordering::Equal) {
return result;
}
Some(::core::cmp::Ordering::Equal)
}
}
享受它吧!
支持的最低Rust版本
许可协议
根据您的选择,许可协议可以是Apache License, Version 2.0或MIT License。
依赖项
约1.5MB
约34K SLoC