Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

issues-721 Add impl IdenStatic and AsRef<str> to #[enum_def] attr #769

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,9 @@ impl Iden for Character {
```

If you're okay with running another procedural macro, you can activate
the `derive` or `attr` feature on the crate to save you some boilerplate.
the `derive` feature on the crate to save you some boilerplate.
For more usage information, look at
[the derive examples](https://github.com/SeaQL/sea-query/tree/master/sea-query-derive/tests/pass)
or [the attribute examples](https://github.com/SeaQL/sea-query/tree/master/sea-query-attr/tests/pass).
[the derive examples](https://github.com/SeaQL/sea-query/tree/master/sea-query-derive/tests/pass).

```rust
#[cfg(feature = "derive")]
Expand All @@ -198,7 +197,7 @@ assert_eq!(Glyph.to_string(), "glyph");
```

```rust
#[cfg(feature = "attr")]
#[cfg(feature = "derive")]
use sea_query::{enum_def, Iden};

#[enum_def]
Expand Down
7 changes: 4 additions & 3 deletions sea-query-attr/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ rust-version = "1.60"
proc-macro = true

[dependencies]
syn = { version = "1", default-features = false }
proc-macro2 = { version = "1", default-features = false }
syn = { version = "2", default-features = false }
quote = { version = "1", default-features = false }
heck = { version = "0.4", default-features = false }
darling = { version = "0.14", default-features = false }
heck = { version = "0.5", default-features = false }
darling = { version = "0.20", default-features = false }

[dev-dependencies]
trybuild = "1.0"
Expand Down
51 changes: 32 additions & 19 deletions sea-query-attr/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
#![allow(clippy::manual_unwrap_or_default)]

use darling::FromMeta;
use darling::{ast::NestedMeta, FromMeta};
use heck::{ToPascalCase, ToSnakeCase};
use proc_macro::TokenStream;
use syn::{
parse_macro_input, spanned::Spanned, AttributeArgs, Data, DataStruct, DeriveInput, Fields,
Ident,
parse_macro_input, punctuated::Punctuated, spanned::Spanned, Data, DataStruct, DeriveInput,
Fields, Ident,
};

type AttributeArgs = Punctuated<NestedMeta, syn::Token![,]>;

struct NamingHolder {
pub default: Ident,
pub pascal: Ident,
Expand Down Expand Up @@ -40,35 +40,48 @@ impl Default for GenEnumArgs {
}
}

#[deprecated(since = "0.1.2", note = "use #[enum_def] attr defined in `sea-query-derive` crate")]
#[proc_macro_attribute]
pub fn enum_def(args: TokenStream, input: TokenStream) -> TokenStream {
let args = parse_macro_input!(args as AttributeArgs);
let args = parse_macro_input!(args with AttributeArgs::parse_terminated);
let input = parse_macro_input!(input as DeriveInput);
let args = GenEnumArgs::from_list(&args).unwrap_or_default();

expand(args, input)
.unwrap_or_else(syn::Error::into_compile_error)
.into()
}

fn expand(attr_args: AttributeArgs, input: DeriveInput) -> syn::Result<proc_macro2::TokenStream> {
let attr_args = attr_args.into_iter().collect::<Vec<_>>();
let args = GenEnumArgs::from_list(&attr_args)?;
let fields = match &input.data {
Data::Struct(DataStruct {
fields: Fields::Named(fields),
..
}) => &fields.named,
_ => panic!("#[enum_def] can only be used on structs"),
_ => {
return Err(syn::Error::new(
input.span(),
"#[enum_def] can only be used on structs",
))
}
};

let field_names: Vec<NamingHolder> = fields
let field_names = fields
.iter()
.map(|field| {
let ident = &field.ident;
let string = ident
.as_ref()
.expect("#[enum_def] can only be used on structs with named fields")
.to_string();
let ident = field.ident.as_ref().ok_or(syn::Error::new(
field.span(),
"#[enum_def] can only be used on structs with named fields",
))?;
let string = ident.to_string();
let as_pascal = string.to_pascal_case();
NamingHolder {
default: ident.as_ref().unwrap().clone(),
syn::Result::Ok(NamingHolder {
default: ident.clone(),
pascal: Ident::new(as_pascal.as_str(), ident.span()),
}
})
})
.collect();
.collect::<syn::Result<Vec<NamingHolder>>>()?;

let table_name = Ident::new(
args.table_name
Expand All @@ -93,7 +106,7 @@ pub fn enum_def(args: TokenStream, input: TokenStream) -> TokenStream {
input.span(),
);

TokenStream::from(quote::quote! {
Ok(quote::quote! {
#input

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
Expand Down
8 changes: 8 additions & 0 deletions sea-query-attr/tests/compile-fail/enum.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use sea_query_attr::enum_def;

#[enum_def]
enum Hello {
Name,
}

fn main() {}
13 changes: 13 additions & 0 deletions sea-query-attr/tests/compile-fail/enum.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: #[enum_def] can only be used on structs
--> tests/compile-fail/enum.rs:4:1
|
4 | enum Hello {
| ^^^^

warning: use of deprecated macro `enum_def`: use #[enum_def] attr defined in `sea-query-derive` crate
--> tests/compile-fail/enum.rs:3:3
|
3 | #[enum_def]
| ^^^^^^^^
|
= note: `#[warn(deprecated)]` on by default
6 changes: 6 additions & 0 deletions sea-query-attr/tests/compile-fail/tuple_struct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use sea_query_attr::enum_def;

#[enum_def]
struct Hello(String);

fn main() {}
13 changes: 13 additions & 0 deletions sea-query-attr/tests/compile-fail/tuple_struct.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: #[enum_def] can only be used on structs
--> tests/compile-fail/tuple_struct.rs:4:1
|
4 | struct Hello(String);
| ^^^^^^

warning: use of deprecated macro `enum_def`: use #[enum_def] attr defined in `sea-query-derive` crate
--> tests/compile-fail/tuple_struct.rs:3:3
|
3 | #[enum_def]
| ^^^^^^^^
|
= note: `#[warn(deprecated)]` on by default
8 changes: 8 additions & 0 deletions sea-query-attr/tests/compile-fail/unknown_field.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use sea_query_attr::enum_def;

#[enum_def(unknown_field)]
pub struct Hello {
pub name: String,
}

fn main() {}
13 changes: 13 additions & 0 deletions sea-query-attr/tests/compile-fail/unknown_field.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
error: Unknown field: `unknown_field`
--> tests/compile-fail/unknown_field.rs:3:12
|
3 | #[enum_def(unknown_field)]
| ^^^^^^^^^^^^^

warning: use of deprecated macro `enum_def`: use #[enum_def] attr defined in `sea-query-derive` crate
--> tests/compile-fail/unknown_field.rs:3:3
|
3 | #[enum_def(unknown_field)]
| ^^^^^^^^
|
= note: `#[warn(deprecated)]` on by default
2 changes: 1 addition & 1 deletion sea-query-attr/tests/test_build.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#[test]
fn build_tests() {
let t = trybuild::TestCases::new();
//t.compile_fail("./tests/compile-fail/*.rs");
t.compile_fail("./tests/compile-fail/*.rs");

// all of these are exactly the same as the examples in `examples/derive.rs`
t.pass("./tests/pass/*.rs");
Expand Down
1 change: 1 addition & 0 deletions sea-query-derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ proc-macro = true
syn = { version = "2", default-features = false, features = ["parsing", "proc-macro", "derive", "printing"] }
quote = { version = "1", default-features = false }
heck = { version = "0.4", default-features = false }
darling = { version = "0.20", default-features = false }
proc-macro2 = { version = "1", default-features = false }
thiserror = { version = "1.0", default-features = false }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::convert::{TryFrom, TryInto};
use syn::spanned::Spanned;
use syn::{Attribute, Error, Expr, ExprLit, Ident, Lit, LitStr, Meta};

use crate::{error::ErrorMsg, iden_path::IdenPath};
use super::{error::ErrorMsg, path::IdenPath};

#[derive(PartialEq, Eq)]
pub(crate) enum IdenAttr {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use syn::Ident;

use crate::iden_path::IdenPath;
use super::path::IdenPath;

#[derive(Debug, thiserror::Error)]
pub enum ErrorMsg {
Expand Down
34 changes: 34 additions & 0 deletions sea-query-derive/src/iden/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
pub(crate) mod attr;
pub(crate) mod error;
pub(crate) mod path;
pub(crate) mod write_arm;

use proc_macro2::TokenStream;
use quote::quote;
use syn::Ident;

use self::write_arm::WriteArm;

pub(crate) struct DeriveIden;

impl WriteArm for DeriveIden {
fn variant(variant: TokenStream, name: TokenStream) -> TokenStream {
quote! { Self::#variant => write!(s, "{}", #name).unwrap() }
}

fn flattened(variant: TokenStream, name: &Ident) -> TokenStream {
quote! { Self::#variant => #name.unquoted(s) }
}
}

pub(crate) struct DeriveIdenStatic;

impl WriteArm for DeriveIdenStatic {
fn variant(variant: TokenStream, name: TokenStream) -> TokenStream {
quote! { Self::#variant => #name }
}

fn flattened(variant: TokenStream, name: &Ident) -> TokenStream {
quote! { Self::#variant => #name.as_str() }
}
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -6,37 +6,13 @@ use proc_macro2::{Span, TokenStream};
use quote::{quote, ToTokens, TokenStreamExt};
use syn::{Error, Fields, FieldsNamed, Ident, Variant};

use crate::{error::ErrorMsg, find_attr, iden_attr::IdenAttr, must_be_valid_iden};
use super::{attr::IdenAttr, error::ErrorMsg};
use crate::{find_attr, must_be_valid_iden};

pub(crate) trait WriteArm {
fn variant(variant: TokenStream, name: TokenStream) -> TokenStream;
fn flattened(variant: TokenStream, name: &Ident) -> TokenStream;
}

pub(crate) struct DeriveIden;

impl WriteArm for DeriveIden {
fn variant(variant: TokenStream, name: TokenStream) -> TokenStream {
quote! { Self::#variant => write!(s, "{}", #name).unwrap() }
}

fn flattened(variant: TokenStream, name: &Ident) -> TokenStream {
quote! { Self::#variant => #name.unquoted(s) }
}
}

pub(crate) struct DeriveIdenStatic;

impl WriteArm for DeriveIdenStatic {
fn variant(variant: TokenStream, name: TokenStream) -> TokenStream {
quote! { Self::#variant => #name }
}

fn flattened(variant: TokenStream, name: &Ident) -> TokenStream {
quote! { Self::#variant => #name.as_str() }
}
}

pub(crate) struct IdenVariant<'a, T> {
ident: &'a Ident,
fields: &'a Fields,
Expand Down Expand Up @@ -183,7 +159,7 @@ where
T::variant(variant, name)
}

pub(super) fn must_be_valid_iden(&self) -> bool {
pub(crate) fn must_be_valid_iden(&self) -> bool {
let name: String = match &self.attr {
Some(a) => match a {
IdenAttr::Rename(name) => name.to_owned(),
Expand Down
Loading