12 releases
0.3.0 | May 25, 2023 |
---|---|
0.2.0 | Aug 18, 2020 |
0.1.0 | Oct 14, 2019 |
0.0.8 | Jun 16, 2019 |
0.0.2 | Apr 23, 2017 |
#43 in Procedural macros
115,355 downloads per month
Used in 113 crates
(58 directly)
30KB
475 lines
Derive Getters
Simple Getters
derive macro for generating field getter methods on a named struct. Included is an additional derive, Dissolve
, that consumes the named struct returning a tuple of all fields in the order they were declared. Any doc comments on the target struct fields are replicated for the corresponding getters. If no comment is present one shall be generated.
The need for the Getters
macro came about when I was making various data structures for JSON to deserialize into. These data structures had many fields in them to access and they weren't going to change once created. One could use pub
everywhere but that would enable mutating the fields which is what this derive aims to avoid.
Getters will be generated according to convention. This means that the generated methods will reside within the struct namespace.
With regards to Dissolve
, sometimes during conversion a structure must be consumed. One easy way to do this is to return a tuple of all the structs fields. Thus Dissolve
can be considered a 'get (move) everything' method call.
What this crate won't do
There are no mutable getters and it's not planned. There are no setters either nor will there ever be.
Rust Docs
Installation
Add to your Cargo.toml
:
[dependencies]
derive-getters = "0.3.0"
Then import the Getters
or Dissolve
macro in whichever module it's needed (assuming 2018 edition).
use derive_getters::{Getters, Dissolve};
Otherwise just import at crate root.
#[macro_use]
extern crate derive_getters;
Usage
When you have a struct you want to automatically derive getters for... Just add the derive at the top like so;
#[derive(Getters)]
pub struct MyCheesyStruct {
x: i64,
y: i64,
}
A new impl will be produced for MyCheesyStruct
.
/// Auto-generated by `derive_getters::Getters`.
impl MyCheesyStruct {
/// Get field `x` from instance of `MyCheesyStruct`.
pub fn x(&self) -> &i64 {
&self.x
}
/// Get field `y` from instance of `MyCheesyStruct`.
pub fn y(&self) -> &i64 {
&self.y
}
}
This crate can also handle structs with simple generic parameters and lifetime annotations. Check docs for further details.
#[derive(Getters)]
pub struct StructWithGeneric<'a, T> {
concrete: f64,
generic: T,
text: &'a str,
}
With Dissolve
, use it like so;
#[derive(Dissolve)]
pub struct Solid {
a: u64,
b: f64,
c: i64,
}
An impl will be produced for Solid
like so;
/// Auto-generated by `derive_getters::Dissolve`.
impl Solid {
/// Dissolve `Solid` into a tuple consisting of its fields in order of declaration.
pub fn dissolve(self) -> (u64, f64, i64) {
(self.a, self.b, self.c)
}
}
Attributes
This macro comes with two optional field attributes for Getters
.
#[getter(skip)]
to skip generating getters for a field.#[getter(rename = "name")]
to change the getter name to "name".
And one optional struct attribute for Dissolve
.
#[dissolve(rename = "name")]
to change the name of the dissolve function to "name".
Comment Preservation
Doc comments on fields shall be copied over onto their respective getters. If there is no comment for the field then one shall be generated.
For example, this struct;
#[derive(Getters, Dissolve)]
#[dissolve(rename = "melt")]
struct Funky<'a, T> {
number: i64,
/// This is commented.
commented: T,
/// This comment is over
/// many lines.
/// Here's another line.
#[getter(rename = "floating")]
many_line: f32,
/**
* This is one of those
* pesky multi-line
* comments.
*/
multi_line: &'a str,
/// We don't care for this field.
#[getter(skip)]
ignore_me: u16,
#[doc = r" A doc comment"]
one_comment: u64,
#[doc = include_str!("../COMMENTS.md")]
incl_comment: u64,
#[doc(hidden)]
/// This comment should be hidden.
hideme: u64,
// This comment won't show up.
bad: u64,
}
Shall have this auto-generated for it;
/// Auto-generated by `derive_getters::Getters`.
impl<'a, T> Funky<'a, T> {
/// Get field `number` from instance of `Funky`.
pub fn number(&self) -> &i64 {
&self.number
}
/// This is commented.
pub fn commented(&self) -> &T {
&self.commented
}
/// This comment is over
/// many lines.
/// Here's another line.
pub fn floating(&self) -> &f32 {
&self.many_line
}
/**
* This is one of those
* pesky multi-line
* comments.
*/
pub fn multi_line(&'a self) -> &'a str {
self.multi_line
}
/// A doc comment
pub fn one_comment(&self) -> &u64 {
&self.one_comment
}
/**Comments sourced from a file included at compile time.
*/
pub fn incl_comment(&self) -> &u64 {
&self.incl_comment
}
#[doc(hidden)]
/// This comment should be hidden.
pub fn hideme(&self) -> &u64 {
&self.hideme
}
/// Get field `bad` from instance of `Funky`.
pub fn bad(&self) -> &u64 {
&self.bad
}
}
/// Auto-generated by `derive_getters::Dissolve`.
impl<'a, T> Funky<'a, T> {
/// Dissolve `Funky` into a tuple consisting of its fields in order of declaration.
pub fn melt(self) -> (i64, T, f32, &'a str, u16, u64, u64, u64, u64) {
(
self.number,
self.commented,
self.many_line,
self.multi_line,
self.ignore_me,
self.one_comment,
self.incl_comment,
self.hideme,
self.bad,
)
}
}
See? Now with comments!
Caveats
- Will not work on unit structs, tuples or enums. Derive
Getters
orDissolve
over them and the macro will chuck a wobbly. - All getter methods return an immutable reference,
&
, to their field. This means for some types it can get awkward.
Alternatives
Dependencies
~1.5MB
~33K SLoC