diff --git a/derive/src/attributes/mod.rs b/derive/src/attributes/mod.rs new file mode 100644 index 0000000..d8412dc --- /dev/null +++ b/derive/src/attributes/mod.rs @@ -0,0 +1,2 @@ +mod row; +pub use row::Row; diff --git a/derive/src/attributes/row.rs b/derive/src/attributes/row.rs new file mode 100644 index 0000000..e08fa71 --- /dev/null +++ b/derive/src/attributes/row.rs @@ -0,0 +1,43 @@ +use quote::ToTokens; + +pub const ATTRIBUTE_NAME: &str = "row"; +pub const ATTRIBUTE_SYNTAX: &str = "#[row(crate = ...)]"; + +pub const CRATE_PATH: &str = "crate"; +pub const DEFAULT_CRATE_PATH: &str = "::clickhouse"; + +pub struct Row { + pub crate_path: syn::Path, +} + +impl Default for Row { + fn default() -> Self { + let default_crate_path = syn::parse_str::(DEFAULT_CRATE_PATH).unwrap(); + Self { + crate_path: default_crate_path, + } + } +} + +impl<'a> TryFrom<&'a syn::Attribute> for Row { + type Error = &'a syn::Attribute; + + fn try_from(attr: &'a syn::Attribute) -> Result { + if attr.path().is_ident(ATTRIBUTE_NAME) { + let row = attr.parse_args::().unwrap(); + let syn::Expr::Assign(syn::ExprAssign { left, right, .. }) = row else { + panic!("expected `{}`", ATTRIBUTE_SYNTAX); + }; + if left.to_token_stream().to_string() != CRATE_PATH { + panic!("expected `{}`", ATTRIBUTE_SYNTAX); + } + let syn::Expr::Path(syn::ExprPath { path, .. }) = *right else { + panic!("expected `{}`", ATTRIBUTE_SYNTAX); + }; + Ok(Self { crate_path: path }) + } else { + return Err(attr); + } + } +} + diff --git a/derive/src/lib.rs b/derive/src/lib.rs index 54ca752..807ce83 100644 --- a/derive/src/lib.rs +++ b/derive/src/lib.rs @@ -1,5 +1,7 @@ +mod attributes; + use proc_macro2::TokenStream; -use quote::{quote, ToTokens}; +use quote::quote; use serde_derive_internals::{ attr::{Container, Default as SerdeDefault, Field}, Ctxt, @@ -7,40 +9,20 @@ use serde_derive_internals::{ use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields}; struct Attributes { - crate_path: syn::Path, + row: attributes::Row, } impl From<&[syn::Attribute]> for Attributes { fn from(attrs: &[syn::Attribute]) -> Self { - const ATTRIBUTE_NAME: &str = "row"; - const ATTRIBUTE_SYNTAX: &str = "#[row(crate = ...)]"; - - const CRATE_PATH: &str = "crate"; - const DEFAULT_CRATE_PATH: &str = "clickhouse"; - - let mut crate_name = None; + let mut row = None; for attr in attrs { - if attr.path().is_ident(ATTRIBUTE_NAME) { - let row = attr.parse_args::().unwrap(); - let syn::Expr::Assign(syn::ExprAssign { left, right, .. }) = row else { - panic!("expected `{}`", ATTRIBUTE_SYNTAX); - }; - if left.to_token_stream().to_string() != CRATE_PATH { - panic!("expected `{}`", ATTRIBUTE_SYNTAX); - } - let syn::Expr::Path(syn::ExprPath { path, .. }) = *right else { - panic!("expected `{}`", ATTRIBUTE_SYNTAX); - }; - crate_name = Some(path); + if let Ok(r) = attributes::Row::try_from(attr) { + row = Some(r); } } - let crate_name = crate_name.unwrap_or_else(|| { - syn::Path::from(syn::Ident::new( - DEFAULT_CRATE_PATH, - proc_macro2::Span::call_site(), - )) - }); - Self { crate_path: crate_name } + Self { + row: row.unwrap_or_default(), + } } } @@ -79,7 +61,9 @@ pub fn row(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(input as DeriveInput); let cx = Ctxt::new(); - let Attributes { crate_path } = Attributes::from(input.attrs.as_slice()); + let Attributes { + row: attributes::Row { crate_path }, + } = Attributes::from(input.attrs.as_slice()); let container = Container::from_ast(&cx, &input); let name = input.ident;