Giter VIP home page Giter VIP logo

getset's People

Contributors

anders429 avatar atul9 avatar bachue avatar cosmichorrordev avatar creepyskeleton avatar dependabot-preview[bot] avatar djc avatar dushistov avatar hoverbear avatar hummer12007 avatar jeizsm avatar pnevyk avatar razican avatar yaahc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

getset's Issues

Feature request: Getters and Setters that implement a Trait

It would be very useful if the getters and Setters could implement a trait fir the structure, instead of adding the implementation directly on the struct.

i.e for:

#[derive(Getters)]
#[getset(trait=GetXY)]
struct Foo {
x: f32
y: f32
}

#[derive(Getters)]
#[getset(trait=GetXY)]
struct Bar {
x: f32
y: f32
}

this would generate:

impl GetXY for Foo {
fn x(&self) -> &f32 {
&self.x
}
fn y(&self) -> &f32 {
&self.y
}
}

impl GetXY for Bar {
fn x(&self) -> &f32 {
&self.x
}
fn y(&self) -> &f32 {
&self.y
}
}

Instead of:

impl Foo {
fn x(&self) -> &f32 {
&self.x
}
fn y(&self) -> &f32 {
&self.y
}
}

impl Bar {
fn x(&self) -> &f32 {
&self.x
}
fn y(&self) -> &f32 {
&self.y
}
}

The attributes could also be field level. E.g

#[derive(Getters)]
struct Bar {
#[getset(trait=GetX)]
x: f32
y: f32
}

This would allow users to create some very powerful abstractions.

For example

fn move(pos: impl GetMutXY, vel: impl GetVelCopy, dt: f32) {
*pos.x() += vel.vx() * dt;
*pos.y() += vel.vy() * dt;
}

This function will work with anything that has getmut getters for x and y, and getcopy getters for vx and vy.

You could create a dynamics library with functions that do not force the user to use a certain datastructure. They could derive the implementations for their own types and then use these functions freely.

This is a more generic solution compared to manually writing custom derives for the traits such as GetMutXY. If you have lots of traits like this, it would be infeasible to write a derive macro for all of them.

Rename get/set functions

I've been using getset on some configuration structs. I use it to derive almost all the getters, but I have some that are boolean and in the struct it makes sense to have them as enable_some_thing or allow_other_thing but when I use a function to query them it is more readable as some_thing_enabled or other_thing_allowed. I could just do the renaming through serde as a work around or just write the functions out like I've been doing instead of using getset but it would be nice to have the ability like serde to rename what is generated. It will probably require the current proc macro api annotations to change, but I think it would be quite useful.

Testing with trybuild

I would highly recommend you to test not only that your crate works where intended but also that it fails where intended. I recommend trybuild for that.

Duplicate definitions when overwriting `get` with `get_copy`

Hey @Hoverbear, thanks for this handy crate ๐Ÿ˜ธ

I noticed that it's not possible to overwrite get with get_copy, e.g.

use getset::{CopyGetters, Getters};

#[derive(Getters, CopyGetters)]
#[get = "pub"]
struct Foo {
    a: String,
    b: String,
    c: String,
    #[get_copy = "pub"]
    d: u64,
}

doesn't compile with

error[E0592]: duplicate definitions with name `d`
 --> src/main.rs:3:19
  |
3 | #[derive(Getters, CopyGetters)]
  |          -------  ^^^^^^^^^^^ duplicate definitions for `d`
  |          |
  |          other definition for `d`
  |
  = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)

error: aborting due to previous error

For more information about this error, try `rustc --explain E0592`.
error: could not compile `foo`

The workaround is to use field level attributes on every property:

use getset::{CopyGetters, Getters};

#[derive(Getters, CopyGetters)]
struct Foo {
    #[get = "pub"]
    a: String,
    #[get = "pub"]
    b: String,
    #[get = "pub"]
    c: String,
    #[get_copy = "pub"]
    d: u64,
}

Suggestion: Enable all attributes (copy-getters, getters, setters) when deriving `GetSet`

Sorry for my long absence, I was very busy..
I'm glad that we now have the way to specify getters that should return by value, but would it be possible to allow the #[get_copy] attribute when only deriving Getters? Not requiring an extra derive (CopyGetters)?

Btw, what was the reason that an extra derive was added for this? I don't think there is any potential for mistakes (like accidentally specifying the wrong kind of getter), and in fact, would it be possible to allow all of getset's attributes just by deriving GetSet?

Sometimes I start out with only deriving Getters and then I add some copy-getter or setter attributes but forget to also derive CopyGetters/Setters and it's one more cargo cycle to notice that..

It would be much more convenient to only have to derive(GetSet), because usually I need getters and setters anyway, and since the goal of this crate is to add convenience & save typing, I think it'd make it even more convenient to enable all attributes at once, what do you think? :)

with_prefix does not work on struct

In the following scenario:

use getset::{Getters, Setters};
#[derive(Default, Getters, Setters)]
#[with_prefix]
#[getset(get="pub with_prefix", set="pub")]
pub struct MyStruct{
 x: f64
}

the method get_x does not get generated.
I also tried this, but it doesn't seem to be handled:

use getset::{Getters, Setters};
#[derive(Default, Getters, Setters)]
#[getset(get="pub with_prefix", set="pub")]
pub struct MyStruct{
 x: f64
}

It is only generated if with_prefix is declared for x like this:

#[derive(Default, Getters, Setters)]
#[getset(set="pub")]use getset::{Getters, Setters};
#[derive(Default, Getters, Setters)]
#[getset(get="pub with_prefix", set="pub")]
pub struct MyStruct{
 x: f64
}

pub struct MyStruct{
 #[get="pub with_prefix"]
 x: f64
}

Using this with Traits

It would be great if there would be an option to use this for Traits. However I think this may require a special syntax(?).

Raw identifiers identifiers don't work properly

#[derive(MutGetters, Setters)]
pub struct Stdio {
    r#in: Option<ChildStdin>,
    out: Option<ChildStdout>,
    err: Option<ChildStderr>,
}

will cause

error: proc-macro derive panicked
   --> src/task.rs:118:10
    |
118 | #[derive(MutGetters, Setters)]
    |          ^^^^^^^^^^
    |
    = help: message: `"r#in_mut"` is not a valid identifier

error: proc-macro derive panicked
   --> src/task.rs:118:22
    |
118 | #[derive(MutGetters, Setters)]
    |                      ^^^^^^^
    |
    = help: message: `"set_r#in"` is not a valid identifier

i know concat_idents macro handles this properly but it's not stable

change attribute style

I think it'd be better to have the attributes like this

#[derive(Getters, Setters, MutGetters)]
struct Hello {
    #[getter(cfgoption1, cfgoption2)]
    #[setter(cfgoption1, cfgoption2)]
    #[mutgetter(cfgoption1, cfgoption2)]
    value: String,
    #[setter(skip)]
    #[getter(skip)]
    #[mutgetter(skip)]
    skipme: (),
}

Essentially it'd be nice to have the same syntax, that derive_builder has :)


It might be better to fuse them into a single trait

#[derive(GetSet)]
struct Hello {
    #[getset(get, set = "pub(crate)", get_mut = "pub")]
    value: String,
    #[getset(hidden)]
    skipme: ()
}

Unary tuple struct getter/setter

Currently getset seems to work with ordinary structs but not with tuple structs:

#[derive(getset::Getters)]
pub struct MyType(u64);
 1  error: Expected the field to have a name
    --> crates/entities/src/newtypes.rs:265:39
     |
 265 | pub struct NonNegativeTimeDeltaMicros(u64);

The following also fails:

#[derive(getset::Getters)]
pub struct MyType(#[getset(get)] u64);

Pitch

It would be convenient to derive get, set, etc for unary tuple structs.
This naming convention has precedent in the standard library. For example, we have std::num::NonZeroU64::get which returns the u64 type that is wrapped by the NonZeroU64 tuple struct.

2 getter impl's for same field

#[derive(Getters, CopyGetters)]
#[getset(get)]
#[cfg_attr(debug_assertions, derive(Debug))]
pub struct Rank {
    #[getset(get_copy)]
    val: RankValue,
    desc: Desc,
}

emits...

    impl Rank {
        #[inline(always)]
        fn val(&self) -> &RankValue {
            &self.val
        }
        #[inline(always)]
        fn desc(&self) -> &Desc {
            &self.desc
        }
    }
    impl Rank {
        #[inline(always)]
        fn val(&self) -> RankValue {
            self.val
        }
    }

The intention is to have all fields get by ref except for val which should get by Copy (without having to revert to specifying at the field-level for all fields).

Documentation

Please, improve the crate documentation.
I suggest adding specific documentation to the derive macros sections, possibly with examples.

In particular the documentation does not say anything about CopyGetters and MutGetters. The signature of the generated methods is not clear for example.

Also the options are not sufficiently described IMO

Propagate fields of inner elements

Often you've structs like

struct MyStruct {
    field_a: TypeA,
    field_b: TypeB
}
struct MyAdvancedStruct {
    inner: MyStruct,
    advanced_a: AdvTypeA,
    advanced_b: AdvTypeB
}

(or even simpler a new-type wrapper like struct MyAdvancedStruct(MyStruct)).

It would be cool if we could easily propagate the fields from the inner structs to the outer struct; e.g. like this:

struct MyAdvancedStruct {
    #[get_inner_pub = "field_a"] inner: MyStruct,
    #[get = "pub"] advanced_a: AdvTypeA,
    #[get = "pub"] advanced_b: AdvTypeB
}

which would create the getters field_a, advanced_a and advanced_b for MyAdvancedStruct.

AFAIK this shouldn't be too hard and I'd be willing to implement this if this is considered to be in the scope of this crate ๐Ÿ˜Š

Release a new version

Hey @Hoverbear ๐Ÿ‘‹, do you think it would be possible to release a new version which contains the latest features? Thank you in advance! ๐Ÿ™

Generic Setter

For example

#[set = "pub"]
struct Hello {
    message: String
}

would generate

impl Hello {
    pub fn set_message(&mut self, value: String) -> &mut Self {
        self.value = value;
        self
    }
}

It'd be nice to have something like this generated instead

impl Hello {
    pub fn set_message<T: Into<String>>(&mut self, value: T) -> &mut Self {
        self.value = value.into();
        self
    }
}

this would allow the user to set more, than just String like &str, &String or Cow<'_, str>.

Maybe this could be enable by adding #[setter(into)] to the struct

#[setter(pub, into)]
struct Hello {
    message: String
}

For reference: derive_builder

support set_copy

support set_copy

#[derive(...)]
pub struct Foo {
 #[set_copy="pub"] 
 bar: bool
}

that will expand like

impl Foo {
  pub fn set_bar(self, bar: bool) -> Self {
    self.bar = bar;
    self
  }
}

primitive types support

It would be convenient,
if for types [ui][8|16|32|64|128], usize, isize, f32,f64,bool
getset will be generat getters that return value, not reference,
example:

#[derive(Debug, Default, Clone, Getters, Setters)]
struct Foo {
    #[get]
    #[set]
    x: f64,
}
fn f() {
    let mut f = Foo::default();
    f.set_x(1.5);
    let x: f64 = f.x();
}

Getter (and Setter?) not compatible with serde(flatten)

I have a struct that uses the attribute #[serde(flatten)] to share fields between multiple structs from an API.

For example, I have this:

#[derive(Deserialize, Getter)]
#[get = "pub"]
struct PartialChapterData {
    id: u64,
    language: String,
}

#[derive(Deserialize, Getters)
#[get = "pub"]
struct UserChapters {
    user_id: u64,
    created: u64, // Unix timestamp
    chapters: Vec<PartialChapterData>,
}

#[derive(Deserialize, Getters)
#[get = "pub"]
struct DetailedChapter {
    #[serde(flatten)]
    chapter_partial: PartialChapterData,
    volume: u16,
    title: String,
}

fn main() {
    let test_json = r#"{
        "id": 1,
        "language": "English",
        "volume": 1,
        "title": "The Chapter Title"
    }"#;

    let detailed_chapter: DetailedChapter = serde_json::from_str(test_json)?;
    println!(
        "Title: {}\nID: {}",
        detailed_chapter.title(), // Does not panic
        detailed_chapter.id(), // Panics with the error: error[E0599]: no method named `id` found for reference `&my_test_crate::v2::responses::chapter::DetailedChapter` in the current scope
    );
}

Is there a correct method or workaround for this? I haven't tested the Setter trait as I don't have a need for it.

Edit 1:
My workaround for now is to manually implement the setters in DetailedChapter like so:

// ...
#[derive(Deserialize, Getter)]
#[get = "pub"]
struct PartialChapterData {
    id: u64,
    language: String,
}

#[derive(Deserialize, Getters)
#[get = "pub"]
struct DetailedChapter {
    #[serde(flatten)]
    chapter_partial: PartialChapterData,
    volume: u16,
    title: String,
}

impl DetailedChapter {
    pub fn id(&self) -> &u64 {
        &self.chapter_partial.id()
    }

    pub fn language(&self) -> &String {
        &self.chapter_partial.language()
    }
}

The other getters .volume() and .title() are generated from getset without needing to re-implement them.

Annotating structs with #[get] or #[set] should propagate to all fields.

This is a really useful library that I've been using quite a bit. Most of the time I want all struct fields to be #[get = "pub"] so being able to annotate a struct would be quite useful. I've come from the Java world where this can be done and there are also negating annotations that prevent getters and setters from being generated or made public, so some syntax like that may be useful.

Specific behaviour for collections.

For example

struct Hello {
    value: Vec<usize>,
}

the value field will be set like any other (set_value(vec)), but it'd be more useful to have something like this additionally;

hello.push_value(1);
hello.set_value(vec![1, 2, 3, 4]);
hello.push_value(5);

assert_eq!(hello.value, vec![1, 2, 3, 4, 5]);

The same could be done for other kinds of collections like HashMap or BTreeMap. (std::collections)

Confusing error when `#[getset(get_copy = "pub")]` is specified but not `derive(CopyGetters)`

When #[getset(get_copy = "pub")] is specified but CopyGetters is not derived (only Getters), the proc-macro doesn't give an error, instead rustc gives the error that foo.bar() is not a method but a field.

Solution: The proc-macro could give an error. But I'd prefer another solution:
Remove CopyGetters altogether, only have Getters, such that get_copy works when Getters is derived. This makes much more sense IMO.
Or is there a reason to require the user to derive CopyGetters / any disadvantages when get_copy is also allowed with Getters?
To me it seems to be more verbose / requiring more typing than necessary, and I often forget to derive CopyGetters.

Release 0.10.0

Hey @Hoverbear wave, do you think it would be possible to release a new version which contains the latest features? Thank you in advance! ๐Ÿ™

Getters/setters for specific traits

Is there any current way to automatically implement getter/setter functions for specific traits? For example, I would like to have a Private trait that relies on having a private() getter:

use getset::{CopyGetters, Getters, MutGetters, Setters};

pub trait Private {
    fn private(&self) -> &i32;
}

#[derive(Getters, Setters, MutGetters, CopyGetters, Default)]
pub struct Foo {
    #[getset(get, set, get_mut)]
    private: i32,
}

impl Private for Foo {};

fn main() {
    let mut foo = Foo::default();
    foo.set_private(1);
    (*foo.private_mut()) += 1;
    assert_eq!(*foo.private(), 2);
}

The above obviously fails unless I do something like:

impl Private for Foo {
    fn private(&self) -> &i32 {
        self.private() 
    }
}

The question is whether there is a way to specify in getset that private() should be implemented for the trait Public and avoid the extra boilerplate. And if not, is this something that could be implemented in the future?

Add Boscop as maintainer

@Boscop, I sent you an invite to join as a maintainer. Feel free to add your name to the crate metadata. ๐Ÿ˜‚ You seem to care and have a vested interest in this, so I value your opinion on the future direction. I don't have your contact details so I resorted to this. :)

If you accept please add yourself to the crate metadata. I can add you to the crates.io project if you'd like to publish as well.

Placing generated getters/setters into impl block?

First of all, thanks for maintaining such a handy crate!

Right now I'm trying to use it implement functions from traits, so I wonder whether it's possible to put the getters/setters into impl blocks? For example, I'd like to do:

trait HasFooSetter {
    fn some_fn_that_modifies_foo(&mut self) {
        self.set_foo("foo".to_owned());
    }
    fn set_foo(&mut self, foo: String) -> &mut Self;
}

#[derive(Setters)]
struct HasFoo {
    #[getset(set = "pub impl=HasFooSetter")]
    foo: String,
}

impl HasFooSetter for HasFoo {}

Generate #[must_use] for getters

Getters don't make sense if their values are unused, and most likely implies a forgotten bug or a misunderstanding of the API.

I am not sure whether marking a function #[must_use] breaks semver BC, but it would be healthy to add more #[must_use].

Setup CI

For example, one of my previous PRs was broken ๐Ÿ˜ข and I didn't notice (yes, the master is broken, sorry). Continuous integration would allow you to catch such cases.

copying/cloning getters?

Are they possible with this crate, how?
E.g. if the field is a primitive type, I often want to copy it in the getter rather than return a ref.

Chaining setters?

Very new to rust, and think this library is really cool.

I wonder if it would be possible to have setters return a reference to self, such that you could chain setters, e.g.:

obj
   .set_foo(2)
   .set_bar(3);

Crate status

Hi, I am a very happy user of this crate. And before anything else, I will say that the current feature set satisfies all my needs, although sometimes I am thinking that having "self-consuming" setters (fn setter(self, value) -> Self) would be nice.

When reading comments in #84 and #87, I saw comments by @Hoverbear that "the features [this crate] offers and the way it does that are [not] very good". Could you or someone else please elaborate on why? Or perhaps say what to use instead (links would suffice)? I am genuinely curious, I may learn something new.

Since I am opening an issue, I will use it for the question about the plan for this crate. As I said, I am happy with the features that are already available. And I would be fine with knowing that the crate is in maintenance mode and no new, especially bigger features like "self-consuming" setters or support for Option<T> fields, will be merged. But would be small maintenance PRs like fixing small bugs or bumping versions of dependencies accepted?

Might be worth considering to put the answer to the readme, too.

Thanks for this helpful tool!

Raw identifiers are not supported

It appears that the Getters derive panics when encountering a raw identifier. The error was reproducible on master as well as the most recently published crates.io version:

ยฑ cargo build
   Compiling getset-bug v0.1.0 (/Users/pwoolcock/code/getset-bug)
thread 'rustc' panicked at '`"r#type"` is not a valid identifier', src/librustc_expand/proc_macro_server.rs:329:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md#bug-reports

note: rustc 1.44.0-nightly (f4c675c47 2020-03-19) running on x86_64-apple-darwin

note: compiler flags: -C debuginfo=2 -C incremental --crate-type lib

note: some of the compiler flags provided by cargo are hidden

error: proc-macro derive panicked
 --> src/lib.rs:3:10
  |
3 | #[derive(Getters)]
  |          ^^^^^^^
  |
  = help: message: `"r#type"` is not a valid identifier

error: aborting due to previous error

error: could not compile `getset-bug`.

To learn more, run the command again with --verbose.

and here's the code I used to generate this error:

use getset::Getters;

#[derive(Getters)]
pub struct Foo {
    r#type: String,
}

Provide ability to create getters that return `A<&T>` instead of `&A<T>`

Thanks for this awesome crate!

#[derive(Default, getset::Getters)]
struct A {
    #[get = "pub"]
    b: Option<B>,
}

#[derive(Default)]
struct B;

fn main() {
    let a = A::default();
    let b: Option<&B> = a.b();
}
error[E0308]: mismatched types
  --> src/main.rs:12:25
   |
12 |     let b: Option<&B> = a.b();
   |            ----------   ^^^^^
   |            |            |
   |            |            expected enum `Option`, found `&Option<B>`
   |            |            help: you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()`: `a.b().as_ref()`
   |            expected due to this
   |
   = note:   expected enum `Option<&B>`
           found reference `&Option<B>`

Getters that return &Option<T> (just like &Result<T>, etc.) are not really useful, as they require getter user to pollute code with .as_ref() everywhere. As alternative, having manual trivial getters like

impl A {
    pub fn b(&self) -> Option<&B> {
        self.b.as_ref()
    }
}

is just another kind of boilerplate code pollution.

Can we do anything with this (and not some breaking change at the same time of course)?

I guess solution would likely require working with each such type separately (perhaps adding OptionGetters and #[get_option = "pub"], etc.), but still this would make this crate more coherent for users.

Writing multiple attributes in one line?

It would be nice to be able to write multiple getset attributes in one line, to reduce verbosity, but when I do (e.g. #[get = "pub", set = "pub"]) the proc-macro panics..

Can you make it work, please? :)

RFC: improve usability: serde like syntax

It would be nice to have serde like syntax.
This make crate is more easy to use, because of many Rust users are already familiar with this syntax, or would be familiar in the near future.

The raw idea:

#[derive(Getset)]
#[getset(setters, getters)]
struct Foo {
#[getset(get_copy)]
f: i32,
#[getset(get_deref=&str)]
a: String,
#[getset(get_deref=&str)]
b: String,
#[getset(skip)]
c: usize,
}

Fluent Setters

I would like to derive fluent, or 'builder' style API

for my use-case I would prefer settings returning Self, but for other use-cases returning &mut Self is probably more appropriate. ideally both would be supported.

get_mut should imply set, which should imply get

I'm using this crate a lot and it's making my struct definitions kinda verbose, so I propose this idea to reduce the verbosity:

Whenever a field has #[set], it should also automatically get a getter, and when it has get_mut it should automatically get a setter and getter, because get_mut already can be used as a setter but the actual set() should be generated for convenience. And we can assume that whenever a field has a setter, the author usually also wants it to have a getter as well. In those rare circumstances when that is not the case, the author can just write a manual setter instead of using the attribute.

What do you think?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.