Skip to content

Commit

Permalink
[refactor] hyperledger-iroha#3882: Update iroha_data_model_derive to …
Browse files Browse the repository at this point in the history
…use syn 2.0

Signed-off-by: Nikita Strygin <[email protected]>
  • Loading branch information
DCNick3 committed Sep 18, 2023
1 parent d111396 commit 092e740
Show file tree
Hide file tree
Showing 18 changed files with 416 additions and 250 deletions.
12 changes: 8 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions data_model/derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ license.workspace = true
proc-macro = true

[dependencies]
syn = { workspace = true, features = ["default", "full", "extra-traits"] }
syn2 = { workspace = true, features = ["default", "full", "extra-traits"] }
quote = { workspace = true }
darling = { workspace = true }
proc-macro2 = { workspace = true }
proc-macro-error = { workspace = true }
manyhow = { workspace = true }
iroha_macro_utils = { workspace = true }
serde_json = { workspace = true, features = ["std"] }

[dev-dependencies]
iroha_data_model = { workspace = true, features = ["http"] }
Expand Down
19 changes: 9 additions & 10 deletions data_model/derive/src/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
clippy::arithmetic_side_effects
)]

use proc_macro::TokenStream;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{
use syn2::{
parse::{Parse, ParseStream},
punctuated::Punctuated,
Attribute, Generics, Ident, Token, Variant, Visibility,
Expand Down Expand Up @@ -113,15 +113,15 @@ impl EventEnum {
}

impl Parse for EventEnum {
fn parse(input: ParseStream) -> syn::Result<Self> {
fn parse(input: ParseStream) -> syn2::Result<Self> {
let _attrs = input.call(Attribute::parse_outer)?;
let vis = input.parse()?;
let _enum_token = input.parse::<Token![enum]>()?;
let ident = input.parse::<Ident>()?;
let generics = input.parse::<Generics>()?;
let content;
let _brace_token = syn::braced!(content in input);
let variants = content.parse_terminated(EventVariant::parse)?;
let _brace_token = syn2::braced!(content in input);
let variants = content.parse_terminated(EventVariant::parse, Token![,])?;
if ident.to_string().ends_with("Event") {
Ok(EventEnum {
vis,
Expand All @@ -130,7 +130,7 @@ impl Parse for EventEnum {
variants,
})
} else {
Err(syn::Error::new_spanned(
Err(syn2::Error::new_spanned(
ident,
"Bad ident: only derivable for `...Event` enums",
))
Expand All @@ -139,7 +139,7 @@ impl Parse for EventEnum {
}

impl Parse for EventVariant {
fn parse(input: ParseStream) -> syn::Result<Self> {
fn parse(input: ParseStream) -> syn2::Result<Self> {
let variant = input.parse::<Variant>()?;
let variant_ident = variant.ident;
let field_type = variant
Expand All @@ -148,7 +148,7 @@ impl Parse for EventVariant {
.next()
.expect("Variant should have at least one unnamed field")
.ty;
if let syn::Type::Path(path) = field_type {
if let syn2::Type::Path(path) = field_type {
let field_ident = path
.path
.get_ident()
Expand All @@ -163,7 +163,7 @@ impl Parse for EventVariant {
Ok(EventVariant::IdField(variant_ident))
}
} else {
Err(syn::Error::new_spanned(
Err(syn2::Error::new_spanned(
field_type,
"Unexpected AST type variant",
))
Expand Down Expand Up @@ -220,7 +220,6 @@ pub fn impl_filter(event: &EventEnum) -> TokenStream {

#event_filter_and_impl
}
.into()
}

/// Generates the event filter for the event. E.g. for `AccountEvent`, `AccountEventFilter`
Expand Down
117 changes: 47 additions & 70 deletions data_model/derive/src/has_origin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,102 +4,80 @@
clippy::unwrap_in_result
)]

use iroha_macro_utils::{attr_struct, AttrParser};
use proc_macro::TokenStream;
use proc_macro_error::abort;
use darling::{FromDeriveInput, FromVariant};
use iroha_macro_utils::{attr_struct2, parse_single_list_attr, parse_single_list_attr_opt};
use manyhow::Result;
use proc_macro2::TokenStream;
use quote::quote;
use syn::{
parse::{Parse, ParseStream},
parse_quote,
punctuated::Punctuated,
Attribute, Generics, Ident, Token, Type, Variant, Visibility,
};
use syn2::{parse_quote, Ident, Token, Type};

mod kw {
syn::custom_keyword!(origin);
syn::custom_keyword!(variant);
syn2::custom_keyword!(origin);
}

const HAS_ORIGIN_ATTR: &str = "has_origin";

pub struct HasOriginEnum {
ident: Ident,
variants: Punctuated<HasOriginVariant, Token![,]>,
variants: Vec<HasOriginVariant>,
origin: Type,
}

impl FromDeriveInput for HasOriginEnum {
fn from_derive_input(input: &syn2::DeriveInput) -> darling::Result<Self> {
let ident = input.ident.clone();

let Some(variants) = darling::ast::Data::<HasOriginVariant, ()>::try_from(&input.data)?.take_enum() else {
return Err(darling::Error::custom("Expected enum"));
};

let origin = parse_single_list_attr::<OriginAttr>(HAS_ORIGIN_ATTR, &input.attrs)?.ty;

Ok(Self {
ident,
variants,
origin,
})
}
}

pub struct HasOriginVariant {
ident: Ident,
extractor: Option<OriginExtractor>,
extractor: Option<OriginExtractorAttr>,
}

struct HasOriginAttr<T>(core::marker::PhantomData<T>);
impl FromVariant for HasOriginVariant {
fn from_variant(variant: &syn2::Variant) -> darling::Result<Self> {
let ident = variant.ident.clone();
let extractor = parse_single_list_attr_opt(HAS_ORIGIN_ATTR, &variant.attrs)?;

impl<T: Parse> AttrParser<T> for HasOriginAttr<T> {
const IDENT: &'static str = "has_origin";
Ok(Self { ident, extractor })
}
}

attr_struct! {
pub struct Origin {
attr_struct2! {
pub struct OriginAttr {
_kw: kw::origin,
_eq: Token![=],
ty: Type,
}
}

attr_struct! {
pub struct OriginExtractor {
attr_struct2! {
pub struct OriginExtractorAttr {
ident: Ident,
_eq: Token![=>],
extractor: syn::Expr,
extractor: syn2::Expr,
}
}

impl Parse for HasOriginEnum {
fn parse(input: ParseStream) -> syn::Result<Self> {
let attrs = input.call(Attribute::parse_outer)?;
let _vis = input.parse::<Visibility>()?;
let _enum_token = input.parse::<Token![enum]>()?;
let ident = input.parse::<Ident>()?;
let generics = input.parse::<Generics>()?;
if !generics.params.is_empty() {
abort!(generics, "Generics are not supported");
}
let content;
let _brace_token = syn::braced!(content in input);
let variants = content.parse_terminated(HasOriginVariant::parse)?;
let origin = attrs
.iter()
.find_map(|attr| HasOriginAttr::<Origin>::parse(attr).ok())
.map(|origin| origin.ty)
.expect("Attribute `#[has_origin(origin = Type)]` is required");
Ok(HasOriginEnum {
ident,
variants,
origin,
})
}
}
pub fn impl_has_origin(input: &syn2::DeriveInput) -> Result<TokenStream> {
let enum_ = HasOriginEnum::from_derive_input(input)?;

impl Parse for HasOriginVariant {
fn parse(input: ParseStream) -> syn::Result<Self> {
let variant = input.parse::<Variant>()?;
let Variant {
ident,
fields,
attrs,
..
} = variant;
match fields {
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {}
fields => abort!(fields, "Only supports tuple variants with single field"),
};
let extractor = attrs
.iter()
.find_map(|attr| HasOriginAttr::<OriginExtractor>::parse(attr).ok());
Ok(HasOriginVariant { ident, extractor })
}
}
// TODO: verify enum is non-empty (or make it work with empty enums)
// TODO: verify all the enum variants are newtype variants
// TODO: verify there are no generics on the enum

pub fn impl_has_origin(enum_: &HasOriginEnum) -> TokenStream {
let enum_ident = &enum_.ident;
let enum_origin = &enum_.origin;
let variants_match_arms = &enum_
Expand All @@ -116,9 +94,9 @@ pub fn impl_has_origin(enum_: &HasOriginEnum) -> TokenStream {
},
)
})
.collect::<Vec<syn::Arm>>();
.collect::<Vec<syn2::Arm>>();

quote! {
Ok(quote! {
impl HasOrigin for #enum_ident {
type Origin = #enum_origin;

Expand All @@ -131,6 +109,5 @@ pub fn impl_has_origin(enum_: &HasOriginEnum) -> TokenStream {
}
}
}
}
.into()
})
}
Loading

0 comments on commit 092e740

Please sign in to comment.