Skip to content

Commit

Permalink
feat(enum): try_into method
Browse files Browse the repository at this point in the history
  • Loading branch information
makcandrov committed Sep 26, 2024
1 parent 62f9515 commit f3e2a91
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 10 deletions.
8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "quick-impl"
version = "0.1.0"
version = "0.1.1"
edition = "2021"
repository = "https://github.com/makcandrov/quick-impl"
homepage = "https://github.com/makcandrov/quick-impl"
Expand All @@ -13,7 +13,7 @@ keywords = ["quick", "impl", "derive"]
proc-macro = true

[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
syn = { version = "2.0", features = ["full"] }
proc-macro2 = "1"
quote = "1"
syn = { version = "2", features = ["full"] }
convert_case = "0.6"
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@
- `as_ref` - Returns an immutable reference to the associated data of the enum variant.
- `as_ref_mut` - Returns a mutable reference to the associated data of the enum variant.
- `from` - Creates an instance of the enum variant from the associated data.
- `into` - Converts the enum into the variant associated data.
- `into` - Converts the enum into the variant associated data, returning an [`Option`].
- `is` - Checks if the enum variant matches a specified variant.
- `try_into` - Converts the enum into the variant associated data, returning a [`Result`].

### Enums traits

Expand Down Expand Up @@ -41,6 +42,8 @@
[`DerefMut`]: https://doc.rust-lang.org/std/ops/trait.DerefMut.html
[`From`]: https://doc.rust-lang.org/std/convert/trait.From.html
[`Into`]: https://doc.rust-lang.org/std/convert/trait.Into.html
[`Option`]: https://doc.rust-lang.org/std/option/enum.Option.html
[`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html

## Usage

Expand Down
3 changes: 3 additions & 0 deletions src/components/enums/methods/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ pub use into::enum_method_into;

mod is;
pub use is::enum_method_is;

mod try_into;
pub use try_into::enum_method_try_into;
51 changes: 51 additions & 0 deletions src/components/enums/methods/try_into.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use proc_macro2::{Delimiter, TokenStream};
use quote::quote;
use syn::Variant;

use crate::attributes::{Attribute, MethodAttribute};
use crate::config::{build_config, build_enum_doc, build_enum_name};
use crate::expand::Context;
use crate::tokens::{destructure_data, destructure_types, get_delimiter};

build_enum_name! { ConfigName, "try_into_{}" }
build_enum_doc! {
ConfigDoc,
"Converts into the associated data if it is the [`{}::{}`] variant. Otherwise, returns `None`.",
}

build_config! {
Config,
(name, ConfigName, true),
(doc, ConfigDoc, false),
}

pub fn enum_method_try_into(
context: &Context,
variant: &Variant,
attribute: &Attribute,
method_attr: &MethodAttribute,
) -> syn::Result<TokenStream> {
let config = Config::new(context, attribute, variant)?;

let fields = &variant.fields;
let delimiter = get_delimiter(fields);

let ty = destructure_types(fields, quote! {}, quote! { () }, false);
let destruct = destructure_data(fields, quote! {}, quote! {}, delimiter, true);
let ret = destructure_data(fields, quote! {}, quote! { () }, Delimiter::Parenthesis, false);

let variant_ident = &variant.ident;
let keywords = method_attr.keywords();
let doc = config.doc;
let method_ident = config.name;

Ok(quote! {
#[doc = #doc]
#keywords fn #method_ident(self) -> Result<#ty, Self> {
match self {
Self::#variant_ident #destruct => Ok(#ret),
item => Err(item),
}
}
})
}
4 changes: 3 additions & 1 deletion src/components/enums/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
use methods::enum_method_try_into;
use syn::DataEnum;

use self::methods::{enum_method_as_ref, enum_method_as_ref_mut, enum_method_from, enum_method_into, enum_method_is};
use self::traits::{enum_trait_default, enum_trait_from};
use crate::attributes::{AttributeType, Attributes};
use crate::expand::{Context, Implems};
use crate::idents::methods::{METHOD_AS_REF, METHOD_AS_REF_MUT, METHOD_FROM, METHOD_INTO, METHOD_IS};
use crate::idents::methods::{METHOD_AS_REF, METHOD_AS_REF_MUT, METHOD_FROM, METHOD_INTO, METHOD_IS, METHOD_TRY_INTO};
use crate::idents::traits::{TRAIT_DEFAULT, TRAIT_FROM};

mod methods;
Expand All @@ -23,6 +24,7 @@ pub fn enum_impl(context: &Context<'_>, implems: &mut Implems, data_enum: &DataE
METHOD_FROM => enum_method_from(context, &variant, attribute, method_attr)?,
METHOD_INTO => enum_method_into(context, &variant, attribute, method_attr)?,
METHOD_IS => enum_method_is(context, &variant, attribute, method_attr)?,
METHOD_TRY_INTO => enum_method_try_into(context, &variant, attribute, method_attr)?,
_ => return Err(syn::Error::new_spanned(&attribute.ident, "Invalid method name.")),
};
implems.extend_methods(tokens);
Expand Down
1 change: 1 addition & 0 deletions src/idents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod methods {
pub const METHOD_INTO: &str = "into";
pub const METHOD_IS: &str = "is";
pub const METHOD_SET: &str = "set";
pub const METHOD_TRY_INTO: &str = "try_into";
pub const METHOD_WITH: &str = "with";
}

Expand Down
9 changes: 5 additions & 4 deletions tests/test_enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use quick_impl::QuickImpl;
fn test_enum_variant_unit() {
#[derive(Debug, Eq, PartialEq, QuickImpl)]
enum Test {
#[quick_impl(pub(crate) const is, const as_ref, pub as_ref_mut, pub(crate) from, pub(crate) into, impl From, impl Default)]
#[quick_impl(pub(crate) const is, const as_ref, pub as_ref_mut, pub(crate) from, pub(crate) into, pub try_into, impl From, impl Default)]
A,
}

Expand All @@ -22,16 +22,17 @@ fn test_enum_variant_unit() {

#[test]
fn test_enum_variant_single_unnamed() {
#[derive(Debug, Eq, PartialEq, QuickImpl)]
#[derive(Debug, Clone, Eq, PartialEq, QuickImpl)]
enum Test {
#[quick_impl(pub(crate) const is, const as_ref, pub as_ref_mut, pub(crate) from, pub(crate) into, impl From, impl Default)]
#[quick_impl(pub(crate) const is, const as_ref, pub as_ref_mut, pub(crate) from, pub(crate) into, pub try_into, impl From, impl Default)]
A(usize),
}

let a = Test::A(12);
assert!(a.is_a());
assert_eq!(*a.as_a().unwrap(), 12);
assert_eq!(a.into_a().unwrap(), 12);
assert_eq!(a.clone().into_a().unwrap(), 12);
assert_eq!(a.try_into_a().unwrap(), 12);

let mut a = Test::A(12);
assert_eq!(*a.as_a_mut().unwrap(), 12);
Expand Down

0 comments on commit f3e2a91

Please sign in to comment.