From 7ec7c3fb2b6d2b3fd4cd90cd67a5cff52d11c5df Mon Sep 17 00:00:00 2001 From: Andrew Sonin Date: Thu, 9 May 2024 20:04:44 +0300 Subject: [PATCH] finalize project for v1.0.0 --- CHANGELOG.md | 16 ++ README.md | 435 ++++++++++++++++++++++++++++++++++ src/field_attribute_layout.rs | 38 +-- src/field_attributes.rs | 14 +- tests/getset.rs | 49 +++- 5 files changed, 518 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2ec4c1..2bdfa6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,4 +6,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 +## [1.0.0] - 2024-05-09 +### Added +- `Getset` procedural macro. +- `Getset` procedural macro field attributes: + - `get` + - `get_mut` + - `get_copy` + - `get_deref` + - `get_deref_mut` + - `get_deref_copy` + - `get_as_ref` + - `get_as_deref` + - `get_as_deref_mut` + - `set` + +[1.0.0]: https://github.com/andrewsonin/gset/releases/tag/v1.0.0 \ No newline at end of file diff --git a/README.md b/README.md index 9b6e818..b948b11 100644 --- a/README.md +++ b/README.md @@ -15,3 +15,438 @@ _Getters and Setters for Rust._ [mit-url]: https://github.com/andrewsonin/gset/blob/main/LICENSE [actions-badge]: https://github.com/andrewsonin/gset/actions/workflows/ci.yml/badge.svg [actions-url]: https://github.com/andrewsonin/gset/actions/workflows/ci.yml + +Provides a procedural macro capable of deriving basic getters and setters for structs. + +## Usage example + +A comprehensive example of using this library is provided below. + +```rust +use gset::Getset; + +#[derive(Getset)] +struct Struct +where + T: Debug, +{ + /// Field 1. + #[getset(get_copy, name = "get_field_1", vis = "pub")] + #[getset(get_mut, vis = "pub")] + #[getset(get, vis = "pub")] + #[getset(set)] + field_1: f64, + + /// Field 2. + #[getset(get_deref, vis = "pub")] + #[getset(get_deref_mut, vis = "pub")] + #[getset(get, name = "get_field_2")] + #[getset(set, vis = "pub")] + field_2: Vec, + + /// Field 3. + #[getset(get_deref_mut, name = "get_field_3", vis = "pub(crate)")] + field_3: Vec, + + /// Field 4. + #[getset(get_deref_copy, name = "get_field_4")] + field_4: F64, + + /// Field 5. + #[getset(get_as_ref, name = "get_field_5", ty = "Option<&F64>")] + #[getset(get_as_deref, name = "get_field_5_deref", ty = "Option<&f64>")] + #[getset( + get_as_deref_mut, + name = "get_field_5_deref_mut", + ty = "Option<&mut f64>" + )] + field_5: Option, +} + +struct F64(f64); + +impl Deref for F64 { + type Target = f64; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for F64 { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} +``` + +This also works well for tuple structures, +but the `name` parameter becomes mandatory. + +```rust +#[derive(Getset)] +struct Struct2( + + /// Field 1. + #[getset(get_copy, name = "get_field_1", vis = "pub")] + #[getset(get_mut, name = "get_field_1_mut", vis = "pub")] + #[getset(get, name = "get_field_1_ref", vis = "pub")] + #[getset(set, name = "set_field_1")] + f64, + + /// Field 2. + #[getset(get_deref, name = "get_field_2", vis = "pub")] + #[getset(get_deref_mut, name = "get_field_2_mut", vis = "pub")] + #[getset(get, name = "get_field_2_ref")] + #[getset(set, name = "set_field_2", vis = "pub")] + Vec, + + /// Field 3. + #[getset(get_deref_mut, name = "get_field_3", vis = "pub(crate)")] + Vec, + + /// Field 4. + #[getset(get_deref_copy, name = "get_field_4")] + F64, + + /// Field 5. + #[getset(get_as_ref, name = "get_field_5", ty = "Option<&F64>")] + #[getset(get_as_deref, name = "get_field_5_deref", ty = "Option<&f64>")] + #[getset( + get_as_deref_mut, + name = "get_field_5_deref_mut", + ty = "Option<&mut f64>" + )] + Option, +) +where + T: Debug; +``` + +## Field attributes supported + +All field attributes have the following named parameters: +- `name` — name of the method being inferred. +Must be a valid Rust [identifier](https://docs.rs/syn/1.0.109/syn/struct.Ident.html). +This is a required parameter for tuple structs. +- `vis` — visibility of the method being inferred. + Must be a valid Rust [visibility modifier](https://docs.rs/syn/1.0.109/syn/enum.Visibility.html). + Visibility is `private` by default. + +And some of them have the following named parameter: +- `ty` — return type of the method being inferred. Must be a valid Rust [type](https://docs.rs/syn/1.0.109/syn/enum.Type.html). + +#### Legend +Here and further we will adhere to the following notation. +- `field` — field name. +- `T` — field type. + +The field attributes currently supported are listed below. + +### 1. `get` + +Derives a reference getter for a field. + +#### Parameters +- `name` — name of the resulting method. If not set, it will be named as `field`. +- `vis` — visibility of the resulting method. If not set, it will be private. +- `ty` — return type of the resulting method. If not set, it will have the `&T` return type. + +#### Example + +```rust +#[derive(Getset)] +struct Struct { + /// Doc comment. + #[getset(get, vis = "pub")] + a: f64, +} +``` +will expand into +```rust +impl Struct { + /// Doc comment. + #[inline] + pub fn a(&self) -> &f64 { + &self.a + } +} +``` + +### 2. `get_mut` + +Derives a mutable getter for a field. + +#### Parameters +- `name` — name of the resulting method. If not set, it will be named as `field_mut`. +- `vis` — visibility of the resulting method. If not set, it will be private. +- `ty` — return type of the resulting method. If not set, it will have the `&mut T` return type. + +#### Example + +```rust +#[derive(Getset)] +struct Struct { + /// Doc comment. + #[getset(get_mut, vis = "pub")] + a: f64, +} +``` +will expand into +```rust +impl Struct { + /// Doc comment. + #[inline] + pub fn a_mut(&mut self) -> &mut f64 { + &mut self.a + } +} +``` + +### 3. `get_copy` + +Derives a copy getter for a field. + +#### Parameters +- `name` — name of the resulting method. If not set, it will be named as `field`. +- `vis` — visibility of the resulting method. If not set, it will be private. +- `ty` — return type of the resulting method. If not set, it will have the `T` return type. + +#### Example + +```rust +#[derive(Getset)] +struct Struct { + /// Doc comment. + #[getset(get_copy, vis = "pub")] + a: f64, +} +``` +will expand into +```rust +impl Struct { + /// Doc comment. + #[inline] + pub fn a(&self) -> f64 { + self.a + } +} +``` + +### 4. `get_deref` + +Derives a reference getter for a field, which applies the `deref` operation to the resulting reference. + +#### Parameters +- `name` — name of the resulting method. If not set, it will be named as `field`. +- `vis` — visibility of the resulting method. If not set, it will be private. +- `ty` — return type of the resulting method. If not set, it will have the `&::Target` return type. + +#### Example + +```rust +#[derive(Getset)] +struct Struct { + /// Doc comment. + #[getset(get_deref, vis = "pub")] + a: Vec, +} +``` +will expand into +```rust +impl Struct { + /// Doc comment. + #[inline] + pub fn a(&self) -> &[f64] { + &self.a + } +} +``` + +### 5. `get_deref_mut` + +Derives a mutable getter for a field, which applies the `deref_mut` operation to the resulting reference. + +#### Parameters +- `name` — name of the resulting method. If not set, it will be named as `field_mut`. +- `vis` — visibility of the resulting method. If not set, it will be private. +- `ty` — return type of the resulting method. If not set, it will have the `&mut ::Target` return type. + +#### Example + +```rust +#[derive(Getset)] +struct Struct { + /// Doc comment. + #[getset(get_deref_mut, vis = "pub")] + a: Vec, +} +``` +will expand into +```rust +impl Struct { + /// Doc comment. + #[inline] + pub fn a_mut(&mut self) -> &mut [f64] { + &mut self.a + } +} +``` + +### 6. `get_deref_copy` + +Derives a copy getter for a field, which applies dereferencing to the field value. + +#### Parameters +- `name` — name of the resulting method. If not set, it will be named as `field`. +- `vis` — visibility of the resulting method. If not set, it will be private. +- `ty` — return type of the resulting method. If not set, it will have the `::Target` return type. + +#### Example + +```rust +#[derive(Getset)] +struct Struct { + /// Doc comment. + #[getset(get_deref_copy, vis = "pub")] + a: F64, +} + +#[derive(Deref)] +struct F64(f64); +``` +will expand into +```rust +impl Struct { + /// Doc comment. + #[inline] + pub fn a(&self) -> f64 { + *self.a + } +} +``` + +### 7. `get_as_ref` + +Derives a reference getter for a field, which applies the `as_ref` operation to the resulting reference. + +#### Parameters +- `name` — name of the resulting method. If not set, it will be named as `field`. +- `vis` — visibility of the resulting method. If not set, it will be private. +- `ty` — required parameter. + +#### Example + +```rust +#[derive(Getset)] +struct Struct { + /// Doc comment. + #[getset(get_as_ref, vis = "pub", ty = "Option<&f64>")] + a: Option, +} +``` +will expand into +```rust +impl Struct { + /// Doc comment. + #[inline] + pub fn a(&self) -> Option<&f64> { + self.a.as_ref() + } +} +``` + +### 8. `get_as_deref` + +Derives a reference getter for a field, which applies the `as_deref` operation to the resulting reference. + +#### Parameters +- `name` — name of the resulting method. If not set, it will be named as `field`. +- `vis` — visibility of the resulting method. If not set, it will be private. +- `ty` — required parameter. + +#### Example + +```rust +#[derive(Getset)] +struct Struct { + /// Doc comment. + #[getset(get_as_deref, vis = "pub", ty = "Option<&f64>")] + a: Option, +} + +#[derive(Deref)] +struct F64(f64); +``` +will expand into +```rust +impl Struct { + /// Doc comment. + #[inline] + pub fn a(&self) -> Option<&f64> { + self.a.as_deref() + } +} +``` + +### 9. `get_as_deref_mut` + +Derives a mutable getter for a field, which applies the `as_deref_mut` operation to the resulting reference. + +#### Parameters +- `name` — name of the resulting method. If not set, it will be named as `field_mut`. +- `vis` — visibility of the resulting method. If not set, it will be private. +- `ty` — required parameter. + +#### Example + +```rust +#[derive(Getset)] +struct Struct { + /// Doc comment. + #[getset(get_as_deref_mut, vis = "pub", ty = "Option<&mut f64>")] + a: Option, +} + +#[derive(Deref, DerefMut)] +struct F64(f64); +``` +will expand into +```rust +impl Struct { + /// Doc comment. + #[inline] + pub fn a_mut(&mut self) -> Option<&mut f64> { + self.a.as_deref_mut() + } +} +``` + +### 10. `set` + +Derives a setter for a field. + +#### Parameters +- `name` — name of the resulting method. If not set, it will be named as `set_field`. +- `vis` — visibility of the resulting method. If not set, it will be private. + +#### Example + +```rust +#[derive(Getset)] +struct Struct { + /// Doc comment. + #[getset(set, vis = "pub")] + a: f64, +} +``` +will expand into +```rust +impl Struct { + /// Doc comment. + #[inline] + pub fn set_a(&mut self, value: f64) { + self.a = value + } +} +``` \ No newline at end of file diff --git a/src/field_attribute_layout.rs b/src/field_attribute_layout.rs index dadc5fe..983dbb1 100644 --- a/src/field_attribute_layout.rs +++ b/src/field_attribute_layout.rs @@ -70,7 +70,7 @@ where } _ => abort!( lit.span(), - "Unknown named attribute. Should be one of: `name`, `vis`, `ty`" + "Unknown named parameter. Should be one of: `name`, `vis`, `ty`" ), } } @@ -150,7 +150,7 @@ impl AttributeLayout { get_ty_override().unwrap_or_else(|| quote! { #field_type }), ) } - AttributeKind::DerefGet => { + AttributeKind::GetDeref => { let fn_name = getter_fn_name(); ( quote! { #fn_name(&self) }, @@ -159,7 +159,7 @@ impl AttributeLayout { .unwrap_or_else(|| quote! { &<#field_type as ::std::ops::Deref>::Target }), ) } - AttributeKind::DerefGetMut => { + AttributeKind::GetDerefMut => { let fn_name = mut_getter_fn_name(); ( quote! { #fn_name(&mut self) }, @@ -169,7 +169,7 @@ impl AttributeLayout { ), ) } - AttributeKind::DerefGetCopy => { + AttributeKind::GetDerefCopy => { let fn_name = getter_fn_name(); ( quote! { #fn_name(&self) }, @@ -178,20 +178,12 @@ impl AttributeLayout { .unwrap_or_else(|| quote! { <#field_type as ::std::ops::Deref>::Target }), ) } - AttributeKind::Set => { - let fn_name = setter_fn_name(); - ( - quote! { #fn_name(&mut self, value: #field_type) }, - quote! { self.#field_ident_or_idx = value }, - get_ty_override().unwrap_or_else(|| quote! { () }), - ) - } - AttributeKind::AsRefGet => { + AttributeKind::GetAsRef => { let fn_name = getter_fn_name(); let ty = get_ty_override().unwrap_or_else(|| { abort!( attr_span(), - "Missed `ty` attribute. Should be set for `as_ref_get` getset kind", + "Missed `ty` named parameter. Should be set for `get_as_ref` getset kind", ) }); ( @@ -200,12 +192,12 @@ impl AttributeLayout { ty, ) } - AttributeKind::AsDerefGet => { + AttributeKind::GetAsDeref => { let fn_name = getter_fn_name(); let ty = get_ty_override().unwrap_or_else(|| { abort!( attr_span(), - "Missed `ty` attribute. Should be set for `as_deref_get` getset kind", + "Missed `ty` named parameter. Should be set for `get_as_deref` getset kind", ) }); ( @@ -214,12 +206,12 @@ impl AttributeLayout { ty, ) } - AttributeKind::AsDerefGetMut => { + AttributeKind::GetAsDerefMut => { let fn_name = mut_getter_fn_name(); let ty = get_ty_override().unwrap_or_else(|| { abort!( attr_span(), - "Missed `ty` attribute. Should be set for `as_deref_get_mut` getset kind", + "Missed `ty` named parameter. Should be set for `get_as_deref_mut` getset kind", ) }); ( @@ -228,6 +220,14 @@ impl AttributeLayout { ty, ) } + AttributeKind::Set => { + let fn_name = setter_fn_name(); + ( + quote! { #fn_name(&mut self, value: #field_type) }, + quote! { self.#field_ident_or_idx = value }, + get_ty_override().unwrap_or_else(|| quote! { () }), + ) + } }; quote! { #visibility fn #signature -> #ty { @@ -252,7 +252,7 @@ where .unwrap_or_else(|| { abort!( attr_span(), - "Missed `name` attribute. \ + "Missed `name` named parameter. \ Should be set for `{}` getset kind when struct ", attr_kind ) diff --git a/src/field_attributes.rs b/src/field_attributes.rs index d8ed1f0..8902e21 100644 --- a/src/field_attributes.rs +++ b/src/field_attributes.rs @@ -62,12 +62,12 @@ define_field_attributes!( Get => "get", GetMut => "get_mut", GetCopy => "get_copy", - DerefGet => "deref_get", - DerefGetMut => "deref_get_mut", - DerefGetCopy => "deref_get_copy", - Set => "set", - AsRefGet => "as_ref_get", - AsDerefGet => "as_deref_get", - AsDerefGetMut => "as_deref_get_mut" + GetDeref => "get_deref", + GetDerefMut => "get_deref_mut", + GetDerefCopy => "get_deref_copy", + GetAsRef => "get_as_ref", + GetAsDeref => "get_as_deref", + GetAsDerefMut => "get_as_deref_mut", + Set => "set" } ); diff --git a/tests/getset.rs b/tests/getset.rs index fe90ba6..47aa08f 100644 --- a/tests/getset.rs +++ b/tests/getset.rs @@ -7,7 +7,7 @@ use std::{ }; #[derive(Getset)] -struct Struct +struct Struct1 where T: Debug, { @@ -19,31 +19,64 @@ where field_1: f64, /// Field 2. - #[getset(deref_get, vis = "pub")] - #[getset(deref_get_mut, vis = "pub")] + #[getset(get_deref, vis = "pub")] + #[getset(get_deref_mut, vis = "pub")] #[getset(get, name = "get_field_2")] #[getset(set, vis = "pub")] field_2: Vec, /// Field 3. - #[getset(deref_get_mut, name = "get_field_3", vis = "pub(crate)")] + #[getset(get_deref_mut, name = "get_field_3", vis = "pub(crate)")] field_3: Vec, /// Field 4. - #[getset(deref_get_copy, name = "get_field_4")] + #[getset(get_deref_copy, name = "get_field_4")] field_4: F64, /// Field 5. - #[getset(as_ref_get, name = "get_field_5", ty = "Option<&F64>")] - #[getset(as_deref_get, name = "get_field_5_deref", ty = "Option<&f64>")] + #[getset(get_as_ref, name = "get_field_5", ty = "Option<&F64>")] + #[getset(get_as_deref, name = "get_field_5_deref", ty = "Option<&f64>")] #[getset( - as_deref_get_mut, + get_as_deref_mut, name = "get_field_5_deref_mut", ty = "Option<&mut f64>" )] field_5: Option, } +#[derive(Getset)] +struct Struct2( + /// Field 1. + #[getset(get_copy, name = "get_field_1", vis = "pub")] + #[getset(get_mut, name = "get_field_1_mut", vis = "pub")] + #[getset(get, name = "get_field_1_ref", vis = "pub")] + #[getset(set, name = "set_field_1")] + f64, + /// Field 2. + #[getset(get_deref, name = "get_field_2", vis = "pub")] + #[getset(get_deref_mut, name = "get_field_2_mut", vis = "pub")] + #[getset(get, name = "get_field_2_ref")] + #[getset(set, name = "set_field_2", vis = "pub")] + Vec, + /// Field 3. + #[getset(get_deref_mut, name = "get_field_3", vis = "pub(crate)")] + Vec, + /// Field 4. + #[getset(get_deref_copy, name = "get_field_4")] + F64, + /// Field 5. + #[getset(get_as_ref, name = "get_field_5", ty = "Option<&F64>")] + #[getset(get_as_deref, name = "get_field_5_deref", ty = "Option<&f64>")] + #[getset( + get_as_deref_mut, + name = "get_field_5_deref_mut", + ty = "Option<&mut f64>" + )] + Option, +) +where + T: Debug; + struct F64(f64); impl Deref for F64 {