![License] ![GitHub Actions] ![Crate Badge] ![Crate Doc] ![MSRV 1.31.0]
Generate several common methods for structs automatically.
Apply the derive proc-macro #[derive(Property)]
to structs, and use #[property(..)]
to configure it.
There are three levels of properties:
Set crate properties can change the default settings for all containers (structs) in the whole crate.
Limited by the procedural macros, here we have to use a tricky way to set the crate properties:
```rust
struct PropertyCrateConf; // This struct is only used for introducing the attribute macro, and it will be removed in the macro. ```
Set container properties can change the default properties for all fields in the container.
Change the settings of a single field via setting field properties.
If no properties is set, the default properties will be applied:
```rust
get(crate, prefix = "", suffix = "", type="auto"),
set(crate, prefix = "set_", type = "ref"),
mut(crate, prefix = "mut_"),
clr(crate, prefix = "clear_", scope = "option")
ord(asc)
)] ```
There are six kinds of configurable properties: skip
, get
, set
, mut
, clr
and ord
.
If the skip
property is set, no methods will be generated.
The visibility of a method can be set via #[property(get(visibility-type))]
There are four kinds of the visibility types: disable
, public
, crate
(default for all methods), and private
.
The method name can be set in two ways:
Assign a complete name via #[property(get(name = "method-name"))]
.
Set prefix
and / or suffix
via #[property(set(prefix = "set_"), mut(suffix = "mut_"))]
.
The default setting for all fields is: #[property(get(prefix = "", suffix = ""), set(prefix = "set_"), mut(prefix = "mut_"))]
.
The return type of get
method can be set via #[property(get(type = "return-type"))]
.
There are four kinds of the return types: auto
(default), ref
, clone
and copy
.
The input type and return type of set
method can be set via #[property(set(type = "set-type"))]
.
There are four kinds of the input types: ref
(default), own
, none
and replace
:
ref
: input is a mutable reference and return is the mutable reference too.
own
: input is a owned object and return is the owned object too.
none
: input is a mutable reference and no return.
replace
: input is a mutable reference and return the old value.
There is an extra property for set
method:
full_option
: if the value is Option<T>
, then the default argument is T
without this property.The clr
method will set a field to its default value. It has a scope
property:
auto
: will generate clr
method for some preset types, such as Vec
, Option
, and so on.
option
: (default) will generate clr
method for Option
only.
all
: will generate clr
method for all types.
If there are more than one filed have the ord
property, the [PartialEq
] and [PartialOrd
] will be implemented automatically.
ord
field property, it's an unsigned number with a _
prefix.The serial numbers could be noncontinuous, but any two number of these could not be equal.
No serial number is allowed if the ord
property is a container property.
asc
and desc
.The default is ascending (asc
), it can be changed to descending if the desc
was set.
```rust
extern crate alloc;
extern crate std as alloc;
use alloc::{string::String, vec::Vec};
use property::{property_default, Property};
struct PropertyCrateConf;
pub enum Species { Dog, Cat, Bird, Other, }
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"))]
familymembers: Vec
rust
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)
}
}
Enjoy it!
[Rust 1.31.0].
Licensed under either of [Apache License, Version 2.0] or [MIT License], at your option.