Browse Source

extract event_err ty info from Flowy_Event macro

appflowy 3 years ago
parent
commit
e998c9a532

+ 3 - 2
rust-lib/flowy-ast/src/ast.rs

@@ -29,7 +29,7 @@ impl<'a> ASTContainer<'a> {
             },
             syn::Data::Enum(data) => {
                 // https://docs.rs/syn/1.0.48/syn/struct.DataEnum.html
-                ASTData::Enum(enum_from_ast(cx, &data.variants))
+                ASTData::Enum(enum_from_ast(cx, &data.variants, &ast.attrs))
             },
         };
 
@@ -209,11 +209,12 @@ pub fn struct_from_ast<'a>(cx: &Ctxt, fields: &'a syn::Fields) -> (ASTStyle, Vec
 pub fn enum_from_ast<'a>(
     cx: &Ctxt,
     variants: &'a Punctuated<syn::Variant, Token![,]>,
+    enum_attrs: &Vec<syn::Attribute>,
 ) -> Vec<ASTEnumVariant<'a>> {
     variants
         .iter()
         .flat_map(|variant| {
-            let attrs = attr::ASTEnumAttrVariant::from_ast(cx, variant);
+            let attrs = attr::ASTEnumAttrVariant::from_ast(cx, variant, enum_attrs);
 
             let (style, fields) = struct_from_ast(cx, &variant.fields);
             Some(ASTEnumVariant {

+ 99 - 55
rust-lib/flowy-ast/src/attr.rs

@@ -5,6 +5,7 @@ use syn::{
     self,
     parse::{self, Parse},
     Meta::{List, NameValue, Path},
+    NestedMeta,
     NestedMeta::{Lit, Meta},
 };
 
@@ -260,6 +261,7 @@ pub enum Default {
 pub struct EventAttrs {
     input: Option<syn::Path>,
     output: Option<syn::Path>,
+    error_ty: Option<String>,
     pub ignore: bool,
 }
 
@@ -271,7 +273,7 @@ pub struct ASTEnumAttrVariant {
 }
 
 impl ASTEnumAttrVariant {
-    pub fn from_ast(ctxt: &Ctxt, variant: &syn::Variant) -> Self {
+    pub fn from_ast(ctxt: &Ctxt, variant: &syn::Variant, enum_attrs: &Vec<syn::Attribute>) -> Self {
         let name = variant.ident.to_string();
         let mut value = String::new();
         if variant.discriminant.is_some() {
@@ -287,60 +289,7 @@ impl ASTEnumAttrVariant {
                 _ => {},
             }
         }
-        let mut event_attrs = EventAttrs {
-            input: None,
-            output: None,
-            ignore: false,
-        };
-        variant.attrs.iter().for_each(|attr| match get_meta_items(ctxt, attr) {
-            Ok(meta_items) => {
-                for meta_item in meta_items {
-                    match &meta_item {
-                        Meta(NameValue(name_value)) => {
-                            if name_value.path == EVENT_INPUT {
-                                if let syn::Lit::Str(s) = &name_value.lit {
-                                    let input_type = parse_lit_str(s)
-                                        .map_err(|_| {
-                                            ctxt.error_spanned_by(
-                                                s,
-                                                format!("failed to parse request deserializer {:?}", s.value()),
-                                            )
-                                        })
-                                        .unwrap();
-                                    event_attrs.input = Some(input_type);
-                                }
-                            }
-
-                            if name_value.path == EVENT_OUTPUT {
-                                if let syn::Lit::Str(s) = &name_value.lit {
-                                    let output_type = parse_lit_str(s)
-                                        .map_err(|_| {
-                                            ctxt.error_spanned_by(
-                                                s,
-                                                format!("failed to parse response deserializer {:?}", s.value()),
-                                            )
-                                        })
-                                        .unwrap();
-                                    event_attrs.output = Some(output_type);
-                                }
-                            }
-                        },
-                        Meta(Path(word)) => {
-                            if word == EVENT_IGNORE && attr.path == EVENT {
-                                event_attrs.ignore = true;
-                            }
-                        },
-                        Lit(s) => {
-                            ctxt.error_spanned_by(s, "unexpected type in cqrs container attribute");
-                        },
-                        _ => {
-                            ctxt.error_spanned_by(meta_item, "unexpected type in cqrs container attribute");
-                        },
-                    }
-                }
-            },
-            Err(_) => {},
-        });
+        let event_attrs = get_event_attrs_from(ctxt, &variant.attrs, enum_attrs);
         ASTEnumAttrVariant {
             name,
             value,
@@ -353,6 +302,101 @@ impl ASTEnumAttrVariant {
     pub fn event_output(&self) -> Option<syn::Path> { self.event_attrs.output.clone() }
 }
 
+fn get_event_attrs_from(
+    ctxt: &Ctxt,
+    variant_attrs: &Vec<syn::Attribute>,
+    enum_attrs: &Vec<syn::Attribute>,
+) -> EventAttrs {
+    let mut event_attrs = EventAttrs {
+        input: None,
+        output: None,
+        error_ty: None,
+        ignore: false,
+    };
+
+    enum_attrs
+        .iter()
+        .filter(|attr| {
+            attr.path
+                .segments
+                .iter()
+                .find(|s| s.ident == EVENT_ERR)
+                .is_some()
+        })
+        .for_each(|attr| {
+            if let Ok(NameValue(named_value)) = attr.parse_meta() {
+                if let syn::Lit::Str(s) = named_value.lit {
+                    event_attrs.error_ty = Some(s.value());
+                } else {
+                    eprintln!("❌ {} should not be empty", EVENT_ERR);
+                }
+            } else {
+                eprintln!("❌ Can not find any {} on attr: {:#?}", EVENT_ERR, attr);
+            }
+        });
+
+    let mut extract_event_attr =
+        |attr: &syn::Attribute, meta_item: &syn::NestedMeta| match &meta_item {
+            Meta(NameValue(name_value)) => {
+                if name_value.path == EVENT_INPUT {
+                    if let syn::Lit::Str(s) = &name_value.lit {
+                        let input_type = parse_lit_str(s)
+                            .map_err(|_| {
+                                ctxt.error_spanned_by(
+                                    s,
+                                    format!("failed to parse request deserializer {:?}", s.value()),
+                                )
+                            })
+                            .unwrap();
+                        event_attrs.input = Some(input_type);
+                    }
+                }
+
+                if name_value.path == EVENT_OUTPUT {
+                    if let syn::Lit::Str(s) = &name_value.lit {
+                        let output_type = parse_lit_str(s)
+                            .map_err(|_| {
+                                ctxt.error_spanned_by(
+                                    s,
+                                    format!(
+                                        "failed to parse response deserializer {:?}",
+                                        s.value()
+                                    ),
+                                )
+                            })
+                            .unwrap();
+                        event_attrs.output = Some(output_type);
+                    }
+                }
+            },
+            Meta(Path(word)) => {
+                if word == EVENT_IGNORE && attr.path == EVENT {
+                    event_attrs.ignore = true;
+                }
+            },
+            Lit(s) => ctxt.error_spanned_by(s, "unexpected attribute"),
+            _ => ctxt.error_spanned_by(meta_item, "unexpected attribute"),
+        };
+
+    let attr_meta_items_info = variant_attrs
+        .iter()
+        .flat_map(|attr| match get_meta_items(ctxt, attr) {
+            Ok(items) => Some((attr, items)),
+            Err(_) => None,
+        })
+        .collect::<Vec<(&syn::Attribute, Vec<syn::NestedMeta>)>>();
+
+    for (attr, nested_metas) in attr_meta_items_info {
+        nested_metas
+            .iter()
+            .for_each(|meta_item| extract_event_attr(attr, meta_item))
+    }
+
+    // eprintln!("😁{:#?}", event_attrs);
+
+    event_attrs
+}
+
 pub fn get_meta_items(cx: &Ctxt, attr: &syn::Attribute) -> Result<Vec<syn::NestedMeta>, ()> {
     if attr.path != PB_ATTRS && attr.path != EVENT {
         return Ok(Vec::new());

+ 1 - 0
rust-lib/flowy-ast/src/symbol.rs

@@ -18,6 +18,7 @@ pub const EVENT_INPUT: Symbol = Symbol("input");
 pub const EVENT_OUTPUT: Symbol = Symbol("output");
 pub const EVENT_IGNORE: Symbol = Symbol("ignore");
 pub const EVENT: Symbol = Symbol("event");
+pub const EVENT_ERR: Symbol = Symbol("event_err");
 
 impl PartialEq<Symbol> for Ident {
     fn eq(&self, word: &Symbol) -> bool { self == word.0 }

+ 2 - 0
rust-lib/flowy-derive/src/dart_event/mod.rs

@@ -1,4 +1,6 @@
 use proc_macro2::TokenStream;
+
+// #[proc_macro_derive(DartEvent, attributes(event_ty))]
 pub fn expand_enum_derive(_input: &syn::DeriveInput) -> Result<TokenStream, Vec<syn::Error>> {
     Ok(TokenStream::default())
 }

+ 1 - 1
rust-lib/flowy-derive/src/lib.rs

@@ -29,7 +29,7 @@ pub fn derive_proto_buf_enum(input: TokenStream) -> TokenStream {
         .into()
 }
 
-#[proc_macro_derive(Flowy_Event, attributes(event))]
+#[proc_macro_derive(Flowy_Event, attributes(event, event_err))]
 pub fn derive_dart_event(input: TokenStream) -> TokenStream {
     let input = parse_macro_input!(input as DeriveInput);
     dart_event::expand_enum_derive(&input)

+ 0 - 7
rust-lib/flowy-user/src/errors.rs

@@ -78,13 +78,6 @@ impl flowy_dispatch::Error for UserError {
     }
 }
 
-macro_rules! static_error {
-    ($name:ident, $status:expr) => {
-        #[allow(non_snake_case, missing_docs)]
-        pub fn $name() -> ErrorBuilder { ErrorBuilder::new($status) }
-    };
-}
-
 pub struct ErrorBuilder {
     pub code: UserErrorCode,
     pub msg: Option<String>,

+ 2 - 1
rust-lib/flowy-user/src/event.rs

@@ -2,6 +2,7 @@ use derive_more::Display;
 use flowy_derive::{Flowy_Event, ProtoBuf_Enum};
 
 #[derive(Clone, Copy, PartialEq, Eq, Debug, Display, Hash, ProtoBuf_Enum, Flowy_Event)]
+#[event_err = "UserError"]
 pub enum UserEvent {
     #[display(fmt = "GetStatus")]
     #[event(output = "UserDetail")]
@@ -13,6 +14,6 @@ pub enum UserEvent {
     #[event(input = "SignUpRequest", output = "UserDetail")]
     SignUp    = 2,
     #[display(fmt = "SignOut")]
-    #[event()]
+    #[event(passthrough)]
     SignOut   = 3,
 }