Upgrading to syn v2 (#1713)

* resetted and re-did the changes

* fmt

* upgraded to syn2 for sea-orm-codegen

* Rename `bae2`

* Drop the use of `#[sea_orm(table_name = "col_name")]` in `DeriveColumn`

* unified derived input metadata parsing filter

* Propagate errors

---------

Co-authored-by: Billy Chan <ccw.billy.123@gmail.com>
This commit is contained in:
darkmmon 2023-06-26 20:15:37 +08:00 committed by GitHub
parent 35c274818b
commit 64342b105c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 252 additions and 357 deletions

View File

@ -18,7 +18,7 @@ path = "src/lib.rs"
[dependencies]
sea-query = { version = "0.29.0-rc.2", default-features = false, features = ["thread-safe"] }
syn = { version = "1", default-features = false, features = ["parsing", "proc-macro", "derive", "printing"] }
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 }
proc-macro2 = { version = "1", default-features = false }

View File

@ -18,8 +18,8 @@ path = "src/lib.rs"
proc-macro = true
[dependencies]
bae = { version = "0.1", default-features = false, optional = true }
syn = { version = "1", default-features = false, features = ["parsing", "proc-macro", "derive", "printing"] }
bae = { version = "1", package = "bae2", default-features = false, optional = 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 }
proc-macro2 = { version = "1", default-features = false }

View File

@ -2,7 +2,7 @@ use super::util::camel_case_with_escaped_non_uax31;
use heck::ToUpperCamelCase;
use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned};
use syn::{parse, punctuated::Punctuated, token::Comma, Expr, Lit, LitInt, LitStr, Meta, UnOp};
use syn::{parse, Expr, Lit, LitInt, LitStr, UnOp};
enum Error {
InputNotEnum,
@ -37,51 +37,46 @@ impl ActiveEnum {
let mut db_type = Err(Error::TT(quote_spanned! {
ident_span => compile_error!("Missing macro attribute `db_type`");
}));
for attr in input.attrs.iter() {
if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" {
continue;
}
} else {
continue;
}
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated) {
for meta in list.iter() {
if let Meta::NameValue(nv) = meta {
if let Some(name) = nv.path.get_ident() {
if name == "rs_type" {
if let Lit::Str(litstr) = &nv.lit {
rs_type = syn::parse_str::<TokenStream>(&litstr.value())
.map_err(Error::Syn);
}
} else if name == "db_type" {
if let Lit::Str(litstr) = &nv.lit {
let s = litstr.value();
match s.as_ref() {
"Enum" => {
db_type = Ok(quote! {
Enum {
name: Self::name(),
variants: Self::iden_values(),
}
})
}
_ => {
db_type = syn::parse_str::<TokenStream>(&s)
.map_err(Error::Syn);
}
input
.attrs
.iter()
.filter(|attr| attr.path().is_ident("sea_orm"))
.try_for_each(|attr| {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("rs_type") {
let litstr: LitStr = meta.value()?.parse()?;
rs_type =
syn::parse_str::<TokenStream>(&litstr.value()).map_err(Error::Syn);
} else if meta.path.is_ident("db_type") {
let litstr: LitStr = meta.value()?.parse()?;
let s = litstr.value();
match s.as_ref() {
"Enum" => {
db_type = Ok(quote! {
Enum {
name: Self::name(),
variants: Self::iden_values(),
}
}
} else if name == "enum_name" {
if let Lit::Str(litstr) = &nv.lit {
enum_name = litstr.value();
}
})
}
_ => {
db_type = syn::parse_str::<TokenStream>(&s).map_err(Error::Syn);
}
}
} else if meta.path.is_ident("enum_name") {
let litstr: LitStr = meta.value()?.parse()?;
enum_name = litstr.value();
} else {
return Err(meta.error(format!(
"Unknown attribute parameter found: {:?}",
meta.path.get_ident()
)));
}
}
}
}
Ok(())
})
.map_err(Error::Syn)
})?;
let variant_vec = match input.data {
syn::Data::Enum(syn::DataEnum { variants, .. }) => variants,
@ -96,33 +91,26 @@ impl ActiveEnum {
let mut string_value = None;
let mut num_value = None;
for attr in variant.attrs.iter() {
if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" {
continue;
}
} else {
if !attr.path().is_ident("sea_orm") {
continue;
}
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)
{
for meta in list {
if let Meta::NameValue(nv) = meta {
if let Some(name) = nv.path.get_ident() {
if name == "string_value" {
if let Lit::Str(lit) = nv.lit {
is_string = true;
string_value = Some(lit);
}
} else if name == "num_value" {
if let Lit::Int(lit) = nv.lit {
is_int = true;
num_value = Some(lit);
}
}
}
}
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("string_value") {
is_string = true;
string_value = Some(meta.value()?.parse::<LitStr>()?);
} else if meta.path.is_ident("num_value") {
is_int = true;
num_value = Some(meta.value()?.parse::<LitInt>()?);
} else {
return Err(meta.error(format!(
"Unknown attribute parameter found: {:?}",
meta.path.get_ident()
)));
}
}
Ok(())
})
.map_err(Error::Syn)?;
}
if is_string && is_int {

View File

@ -4,11 +4,7 @@ use super::util::{
use heck::ToUpperCamelCase;
use proc_macro2::{Ident, TokenStream};
use quote::{format_ident, quote, quote_spanned};
use syn::{
punctuated::{IntoIter, Punctuated},
token::Comma,
Data, DataStruct, Field, Fields, Lit, Meta, Type,
};
use syn::{punctuated::IntoIter, Data, DataStruct, Expr, Field, Fields, LitStr, Type};
/// Method to derive an [ActiveModel](sea_orm::ActiveModel)
pub fn expand_derive_active_model(ident: Ident, data: Data) -> syn::Result<TokenStream> {
@ -47,32 +43,28 @@ fn derive_active_model(all_fields: IntoIter<Field>) -> syn::Result<TokenStream>
let ident = trim_starting_raw_identifier(ident).to_upper_camel_case();
let ident = escape_rust_keyword(ident);
let mut ident = format_ident!("{}", &ident);
for attr in field.attrs.iter() {
if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" {
continue;
}
} else {
continue;
}
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)
{
for meta in list.iter() {
if let Meta::NameValue(nv) = meta {
if let Some(name) = nv.path.get_ident() {
if name == "enum_name" {
if let Lit::Str(litstr) = &nv.lit {
ident = syn::parse_str(&litstr.value()).unwrap();
}
}
}
field
.attrs
.iter()
.filter(|attr| attr.path().is_ident("sea_orm"))
.try_for_each(|attr| {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("enum_name") {
let litstr: LitStr = meta.value()?.parse()?;
ident = syn::parse_str(&litstr.value()).unwrap();
} else {
// Reads the value expression to advance the parse stream.
// Some parameters, such as `primary_key`, do not have any value,
// so ignoring an error occurred here.
let _: Option<Expr> = meta.value().and_then(|v| v.parse()).ok();
}
}
}
}
ident
Ok(())
})
})?;
Ok::<Ident, syn::Error>(ident)
})
.collect();
.collect::<Result<_, _>>()?;
let ty: Vec<Type> = fields.into_iter().map(|Field { ty, .. }| ty).collect();

View File

@ -1,7 +1,7 @@
use heck::{ToLowerCamelCase, ToSnakeCase};
use proc_macro2::{Ident, TokenStream};
use quote::{quote, quote_spanned};
use syn::{punctuated::Punctuated, token::Comma, Data, DataEnum, Fields, Lit, Meta, Variant};
use syn::{Data, DataEnum, Expr, Fields, LitStr, Variant};
/// Derive a Column name for an enum type
pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result<TokenStream> {
@ -28,36 +28,24 @@ pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result<TokenStrea
.map(|v| {
let mut column_name = v.ident.to_string().to_snake_case();
for attr in v.attrs.iter() {
if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" {
continue;
}
} else {
if !attr.path().is_ident("sea_orm") {
continue;
}
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)
{
for meta in list.iter() {
if let Meta::NameValue(nv) = meta {
if let Some(name) = nv.path.get_ident() {
if name == "column_name" {
if let Lit::Str(litstr) = &nv.lit {
column_name = litstr.value();
}
}
if name == "table_name" {
if let Lit::Str(litstr) = &nv.lit {
column_name = litstr.value();
}
}
}
}
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("column_name") {
column_name = meta.value()?.parse::<LitStr>()?.value();
} else {
// Reads the value expression to advance the parse stream.
// Some parameters, such as `primary_key`, do not have any value,
// so ignoring an error occurred here.
let _: Option<Expr> = meta.value().and_then(|v| v.parse()).ok();
}
}
Ok(())
})?;
}
quote! { #column_name }
Ok::<TokenStream, syn::Error>(quote! { #column_name })
})
.collect();
.collect::<Result<_, _>>()?;
Ok(quote!(
#[automatically_derived]

View File

@ -3,8 +3,8 @@ use heck::{ToSnakeCase, ToUpperCamelCase};
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, quote_spanned};
use syn::{
parse::Error, punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, Fields,
Lit, LitStr, Meta, Type,
punctuated::Punctuated, spanned::Spanned, token::Comma, Attribute, Data, Expr, Fields, Lit,
LitStr, Type,
};
/// Method to derive an Model
@ -13,32 +13,28 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
let mut table_name = None;
let mut schema_name = quote! { None };
let mut table_iden = false;
attrs.iter().for_each(|attr| {
if attr.path.get_ident().map(|i| i == "sea_orm") != Some(true) {
return;
}
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated) {
for meta in list.iter() {
if let Meta::NameValue(nv) = meta {
if let Some(ident) = nv.path.get_ident() {
if ident == "table_name" {
table_name = Some(nv.lit.clone());
} else if ident == "schema_name" {
let name = &nv.lit;
schema_name = quote! { Some(#name) };
}
}
} else if let Meta::Path(path) = meta {
if let Some(ident) = path.get_ident() {
if ident == "table_iden" {
table_iden = true;
}
}
attrs
.iter()
.filter(|attr| attr.path().is_ident("sea_orm"))
.try_for_each(|attr| {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("table_name") {
table_name = Some(meta.value()?.parse::<Lit>()?);
} else if meta.path.is_ident("schema_name") {
let name: Lit = meta.value()?.parse()?;
schema_name = quote! { Some(#name) };
} else if meta.path.is_ident("table_iden") {
table_iden = true;
} else {
// Reads the value expression to advance the parse stream.
// Some parameters, such as `primary_key`, do not have any value,
// so ignoring an error occurred here.
let _: Option<Expr> = meta.value().and_then(|v| v.parse()).ok();
}
}
}
});
Ok(())
})
})?;
let entity_def = table_name
.as_ref()
.map(|table_name| {
@ -114,111 +110,86 @@ pub fn expand_derive_entity_model(data: Data, attrs: Vec<Attribute>) -> syn::Res
let mut is_primary_key = false;
// search for #[sea_orm(primary_key, auto_increment = false, column_type = "String(Some(255))", default_value = "new user", default_expr = "gen_random_uuid()", column_name = "name", enum_name = "Name", nullable, indexed, unique)]
for attr in field.attrs.iter() {
if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" {
continue;
}
} else {
if !attr.path().is_ident("sea_orm") {
continue;
}
// single param
if let Ok(list) =
attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)
{
for meta in list.iter() {
match meta {
Meta::NameValue(nv) => {
if let Some(name) = nv.path.get_ident() {
if name == "column_type" {
if let Lit::Str(litstr) = &nv.lit {
let ty: TokenStream =
syn::parse_str(&litstr.value())?;
sql_type = Some(ty);
} else {
return Err(Error::new(
field.span(),
format!("Invalid column_type {:?}", nv.lit),
));
}
} else if name == "auto_increment" {
if let Lit::Bool(litbool) = &nv.lit {
auto_increment = litbool.value();
} else {
return Err(Error::new(
field.span(),
format!(
"Invalid auto_increment = {:?}",
nv.lit
),
));
}
} else if name == "default_value" {
default_value = Some(nv.lit.to_owned());
} else if name == "default_expr" {
default_expr = Some(nv.lit.to_owned());
} else if name == "column_name" {
if let Lit::Str(litstr) = &nv.lit {
column_name = Some(litstr.value());
} else {
return Err(Error::new(
field.span(),
format!("Invalid column_name {:?}", nv.lit),
));
}
} else if name == "enum_name" {
if let Lit::Str(litstr) = &nv.lit {
let ty: Ident =
syn::parse_str(&litstr.value())?;
enum_name = Some(ty);
} else {
return Err(Error::new(
field.span(),
format!("Invalid enum_name {:?}", nv.lit),
));
}
} else if name == "select_as" {
if let Lit::Str(litstr) = &nv.lit {
select_as = Some(litstr.value());
} else {
return Err(Error::new(
field.span(),
format!("Invalid select_as {:?}", nv.lit),
));
}
} else if name == "save_as" {
if let Lit::Str(litstr) = &nv.lit {
save_as = Some(litstr.value());
} else {
return Err(Error::new(
field.span(),
format!("Invalid save_as {:?}", nv.lit),
));
}
}
}
}
Meta::Path(p) => {
if let Some(name) = p.get_ident() {
if name == "ignore" {
ignore = true;
break;
} else if name == "primary_key" {
is_primary_key = true;
primary_key_types.push(field.ty.clone());
} else if name == "nullable" {
nullable = true;
} else if name == "indexed" {
indexed = true;
} else if name == "unique" {
unique = true;
}
}
}
_ => {}
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("column_type") {
let lit = meta.value()?.parse()?;
if let Lit::Str(litstr) = lit {
let ty: TokenStream = syn::parse_str(&litstr.value())?;
sql_type = Some(ty);
} else {
return Err(
meta.error(format!("Invalid column_type {:?}", lit))
);
}
} else if meta.path.is_ident("auto_increment") {
let lit = meta.value()?.parse()?;
if let Lit::Bool(litbool) = lit {
auto_increment = litbool.value();
} else {
return Err(
meta.error(format!("Invalid auto_increment = {:?}", lit))
);
}
} else if meta.path.is_ident("default_value") {
default_value = Some(meta.value()?.parse::<Lit>()?);
} else if meta.path.is_ident("default_expr") {
default_expr = Some(meta.value()?.parse::<Lit>()?);
} else if meta.path.is_ident("column_name") {
let lit = meta.value()?.parse()?;
if let Lit::Str(litstr) = lit {
column_name = Some(litstr.value());
} else {
return Err(
meta.error(format!("Invalid column_name {:?}", lit))
);
}
} else if meta.path.is_ident("enum_name") {
let lit = meta.value()?.parse()?;
if let Lit::Str(litstr) = lit {
let ty: Ident = syn::parse_str(&litstr.value())?;
enum_name = Some(ty);
} else {
return Err(meta.error(format!("Invalid enum_name {:?}", lit)));
}
} else if meta.path.is_ident("select_as") {
let lit = meta.value()?.parse()?;
if let Lit::Str(litstr) = lit {
select_as = Some(litstr.value());
} else {
return Err(meta.error(format!("Invalid select_as {:?}", lit)));
}
} else if meta.path.is_ident("save_as") {
let lit = meta.value()?.parse()?;
if let Lit::Str(litstr) = lit {
save_as = Some(litstr.value());
} else {
return Err(meta.error(format!("Invalid save_as {:?}", lit)));
}
} else if meta.path.is_ident("ignore") {
ignore = true;
} else if meta.path.is_ident("primary_key") {
is_primary_key = true;
primary_key_types.push(field.ty.clone());
} else if meta.path.is_ident("nullable") {
nullable = true;
} else if meta.path.is_ident("indexed") {
indexed = true;
} else if meta.path.is_ident("unique") {
unique = true;
} else {
// Reads the value expression to advance the parse stream.
// Some parameters, such as `primary_key`, do not have any value,
// so ignoring an error occurred here.
let _: Option<Expr> = meta.value().and_then(|v| v.parse()).ok();
}
}
Ok(())
})?;
}
if let Some(enum_name) = enum_name {

View File

@ -6,7 +6,7 @@ use heck::ToUpperCamelCase;
use proc_macro2::TokenStream;
use quote::{format_ident, quote, quote_spanned};
use std::iter::FromIterator;
use syn::{punctuated::Punctuated, token::Comma, Ident, Lit, Meta};
use syn::{Expr, Ident, LitStr};
enum Error {
InputNotStruct,
@ -50,33 +50,29 @@ impl DeriveModel {
let ident = trim_starting_raw_identifier(ident).to_upper_camel_case();
let ident = escape_rust_keyword(ident);
let mut ident = format_ident!("{}", &ident);
for attr in field.attrs.iter() {
if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" {
continue;
}
} else {
continue;
}
if let Ok(list) =
attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)
{
for meta in list.iter() {
if let Meta::NameValue(nv) = meta {
if let Some(name) = nv.path.get_ident() {
if name == "enum_name" {
if let Lit::Str(litstr) = &nv.lit {
ident = syn::parse_str(&litstr.value()).unwrap();
}
}
}
field
.attrs
.iter()
.filter(|attr| attr.path().is_ident("sea_orm"))
.try_for_each(|attr| {
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("enum_name") {
ident = syn::parse_str(&meta.value()?.parse::<LitStr>()?.value())
.unwrap();
} else {
// Reads the value expression to advance the parse stream.
// Some parameters, such as `primary_key`, do not have any value,
// so ignoring an error occurred here.
let _: Option<Expr> = meta.value().and_then(|v| v.parse()).ok();
}
}
}
}
ident
Ok(())
})
.map_err(Error::Syn)
})?;
Ok(ident)
})
.collect();
.collect::<Result<_, _>>()?;
let ignore_attrs = fields
.iter()

View File

@ -50,11 +50,7 @@ impl DerivePartialModel {
let mut entity_ident = None;
for attr in input.attrs.iter() {
if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" {
continue;
}
} else {
if !attr.path().is_ident("sea_orm") {
continue;
}
@ -77,7 +73,7 @@ impl DerivePartialModel {
let mut from_expr = None;
for attr in field.attrs.iter() {
if !attr.path.is_ident("sea_orm") {
if !attr.path().is_ident("sea_orm") {
continue;
}
@ -192,7 +188,7 @@ pub fn expand_derive_partial_model(input: syn::DeriveInput) -> syn::Result<Token
}
mod util {
use syn::{Lit, Meta, MetaNameValue};
use syn::{Meta, MetaNameValue};
pub(super) trait GetAsKVMeta {
fn get_as_kv(&self, k: &str) -> Option<String>;
@ -200,12 +196,14 @@ mod util {
impl GetAsKVMeta for Meta {
fn get_as_kv(&self, k: &str) -> Option<String> {
let Meta::NameValue(MetaNameValue{path, lit:Lit::Str(lit), ..}) = self else {
let Meta::NameValue(MetaNameValue{path, value: syn::Expr::Lit(exprlit), ..}) = self else {
return None;
};
let syn::Lit::Str(litstr) = &exprlit.lit else { return None; };
if path.is_ident(k) {
Some(lit.value())
Some(litstr.value())
} else {
None
}

View File

@ -1,7 +1,7 @@
use heck::ToSnakeCase;
use proc_macro2::{Ident, TokenStream};
use quote::{quote, quote_spanned};
use syn::{punctuated::Punctuated, token::Comma, Data, DataEnum, Fields, Lit, Meta, Variant};
use syn::{Data, DataEnum, Expr, Fields, LitStr, Variant};
/// Method to derive a Primary Key for a Model using the [PrimaryKeyTrait](sea_orm::PrimaryKeyTrait)
pub fn expand_derive_primary_key(ident: Ident, data: Data) -> syn::Result<TokenStream> {
@ -34,31 +34,26 @@ pub fn expand_derive_primary_key(ident: Ident, data: Data) -> syn::Result<TokenS
.map(|v| {
let mut column_name = v.ident.to_string().to_snake_case();
for attr in v.attrs.iter() {
if let Some(ident) = attr.path.get_ident() {
if ident != "sea_orm" {
continue;
}
} else {
if !attr.path().is_ident("sea_orm") {
continue;
}
if let Ok(list) = attr.parse_args_with(Punctuated::<Meta, Comma>::parse_terminated)
{
for meta in list.iter() {
if let Meta::NameValue(nv) = meta {
if let Some(name) = nv.path.get_ident() {
if name == "column_name" {
if let Lit::Str(litstr) = &nv.lit {
column_name = litstr.value();
}
}
}
}
attr.parse_nested_meta(|meta| {
if meta.path.is_ident("column_name") {
column_name = meta.value()?.parse::<LitStr>()?.value();
} else {
// Reads the value expression to advance the parse stream.
// Some parameters, such as `primary_key`, do not have any value,
// so ignoring an error occurred here.
let _: Option<Expr> = meta.value().and_then(|v| v.parse()).ok();
}
}
Ok(())
})?;
}
quote! { #column_name }
Ok::<TokenStream, syn::Error>(quote! { #column_name })
})
.collect();
.collect::<Result<_, _>>()?;
Ok(quote!(
#[automatically_derived]

View File

@ -4,7 +4,7 @@ use syn::{punctuated::Punctuated, token::Comma, Field, Ident, Meta};
pub(crate) fn field_not_ignored(field: &Field) -> bool {
for attr in field.attrs.iter() {
if let Some(ident) = attr.path.get_ident() {
if let Some(ident) = attr.path().get_ident() {
if ident != "sea_orm" {
continue;
}

View File

@ -1,12 +1,11 @@
use proc_macro2::{Span, TokenStream};
use proc_macro2::TokenStream;
use syn::{
parenthesized,
parse::{Parse, ParseStream},
parse2, parse_str,
punctuated::Punctuated,
spanned::Spanned,
Attribute, DeriveInput, Ident, Lit, LitBool, LitStr, Meta, MetaNameValue, Path, Token, Variant,
Visibility,
Attribute, DeriveInput, Expr, ExprLit, Ident, Lit, LitBool, LitStr, Meta, MetaNameValue, Path,
Token, Variant, Visibility,
};
use super::case_style::CaseStyle;
@ -76,17 +75,6 @@ impl Parse for EnumMeta {
}
}
impl Spanned for EnumMeta {
fn span(&self) -> Span {
match self {
EnumMeta::SerializeAll { kw, .. } => kw.span(),
EnumMeta::AsciiCaseInsensitive(kw) => kw.span(),
EnumMeta::Crate { kw, .. } => kw.span(),
EnumMeta::UsePhf(use_phf) => use_phf.span(),
}
}
}
pub enum EnumDiscriminantsMeta {
Derive { kw: kw::derive, paths: Vec<Path> },
Name { kw: kw::name, name: Ident },
@ -100,7 +88,7 @@ impl Parse for EnumDiscriminantsMeta {
let kw = input.parse()?;
let content;
parenthesized!(content in input);
let paths = content.parse_terminated::<_, Token![,]>(Path::parse)?;
let paths = content.parse_terminated(Path::parse, Token![,])?;
Ok(EnumDiscriminantsMeta::Derive {
kw,
paths: paths.into_iter().collect(),
@ -127,17 +115,6 @@ impl Parse for EnumDiscriminantsMeta {
}
}
impl Spanned for EnumDiscriminantsMeta {
fn span(&self) -> Span {
match self {
EnumDiscriminantsMeta::Derive { kw, .. } => kw.span,
EnumDiscriminantsMeta::Name { kw, .. } => kw.span,
EnumDiscriminantsMeta::Vis { kw, .. } => kw.span,
EnumDiscriminantsMeta::Other { path, .. } => path.span(),
}
}
}
pub trait DeriveInputExt {
/// Get all the strum metadata associated with an enum.
fn get_metadata(&self) -> syn::Result<Vec<EnumMeta>>;
@ -228,7 +205,7 @@ impl Parse for VariantMeta {
let kw = input.parse()?;
let content;
parenthesized!(content in input);
let props = content.parse_terminated::<_, Token![,]>(Prop::parse)?;
let props = content.parse_terminated(Prop::parse, Token![,])?;
Ok(VariantMeta::Props {
kw,
props: props
@ -256,22 +233,6 @@ impl Parse for Prop {
}
}
impl Spanned for VariantMeta {
fn span(&self) -> Span {
match self {
VariantMeta::Message { kw, .. } => kw.span,
VariantMeta::DetailedMessage { kw, .. } => kw.span,
VariantMeta::Documentation { value } => value.span(),
VariantMeta::Serialize { kw, .. } => kw.span,
VariantMeta::ToString { kw, .. } => kw.span,
VariantMeta::Disabled(kw) => kw.span,
VariantMeta::Default(kw) => kw.span,
VariantMeta::AsciiCaseInsensitive { kw, .. } => kw.span,
VariantMeta::Props { kw, .. } => kw.span,
}
}
}
pub trait VariantExt {
/// Get all the metadata associated with an enum variant.
fn get_metadata(&self) -> syn::Result<Vec<VariantMeta>>;
@ -282,26 +243,32 @@ impl VariantExt for Variant {
let result = get_metadata_inner("strum", &self.attrs)?;
self.attrs
.iter()
.filter(|attr| attr.path.is_ident("doc"))
.filter(|attr| attr.path().is_ident("doc"))
.try_fold(result, |mut vec, attr| {
if let Meta::NameValue(MetaNameValue {
lit: Lit::Str(value),
value:
Expr::Lit(ExprLit {
lit: Lit::Str(value),
..
}),
..
}) = attr.parse_meta()?
}) = &attr.meta
{
vec.push(VariantMeta::Documentation { value })
vec.push(VariantMeta::Documentation {
value: value.clone(),
})
}
Ok(vec)
})
}
}
fn get_metadata_inner<'a, T: Parse + Spanned>(
fn get_metadata_inner<'a, T: Parse>(
ident: &str,
it: impl IntoIterator<Item = &'a Attribute>,
) -> syn::Result<Vec<T>> {
it.into_iter()
.filter(|attr| attr.path.is_ident(ident))
.filter(|attr| attr.path().is_ident(ident))
.try_fold(Vec::new(), |mut vec, attr| {
vec.extend(attr.parse_args_with(Punctuated::<T, Token![,]>::parse_terminated)?);
Ok(vec)