-
Notifications
You must be signed in to change notification settings - Fork 101
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
derive: Support #[row(crate = ...)]
#189
base: main
Are you sure you want to change the base?
Changes from 4 commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
mod row; | ||
pub use row::Row; | ||
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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::<syn::Path>(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<Self, Self::Error> { | ||
if attr.path().is_ident(ATTRIBUTE_NAME) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not very important (because it's a private API), but it's more straightforward to return an error (even a simple string) and panic in the |
||
let row = attr.parse_args::<syn::Expr>().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); | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
mod attributes; | ||
|
||
use proc_macro2::TokenStream; | ||
use quote::quote; | ||
use serde_derive_internals::{ | ||
|
@@ -6,6 +8,24 @@ use serde_derive_internals::{ | |
}; | ||
use syn::{parse_macro_input, Data, DataStruct, DeriveInput, Fields}; | ||
|
||
struct Attributes { | ||
row: attributes::Row, | ||
} | ||
|
||
impl From<&[syn::Attribute]> for Attributes { | ||
fn from(attrs: &[syn::Attribute]) -> Self { | ||
let mut row = None; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is point to use |
||
for attr in attrs { | ||
if let Ok(r) = attributes::Row::try_from(attr) { | ||
row = Some(r); | ||
} | ||
} | ||
Self { | ||
row: row.unwrap_or_default(), | ||
} | ||
} | ||
} | ||
|
||
fn column_names(data: &DataStruct, cx: &Ctxt, container: &Container) -> TokenStream { | ||
match &data.fields { | ||
Fields::Named(fields) => { | ||
|
@@ -36,11 +56,14 @@ fn column_names(data: &DataStruct, cx: &Ctxt, container: &Container) -> TokenStr | |
// TODO: support wrappers `Wrapper(Inner)` and `Wrapper<T>(T)`. | ||
// TODO: support the `nested` attribute. | ||
// TODO: support the `crate` attribute. | ||
YBoy-git marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#[proc_macro_derive(Row)] | ||
#[proc_macro_derive(Row, attributes(row))] | ||
pub fn row(input: proc_macro::TokenStream) -> proc_macro::TokenStream { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This patch deserves a docstring |
||
let input = parse_macro_input!(input as DeriveInput); | ||
|
||
let cx = Ctxt::new(); | ||
let Attributes { | ||
row: attributes::Row { crate_path }, | ||
} = Attributes::from(input.attrs.as_slice()); | ||
let container = Container::from_ast(&cx, &input); | ||
let name = input.ident; | ||
|
||
|
@@ -54,10 +77,9 @@ pub fn row(input: proc_macro::TokenStream) -> proc_macro::TokenStream { | |
|
||
let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); | ||
|
||
// TODO: replace `clickhouse` with `::clickhouse` here. | ||
let expanded = quote! { | ||
#[automatically_derived] | ||
impl #impl_generics clickhouse::Row for #name #ty_generics #where_clause { | ||
impl #impl_generics #crate_path::Row for #name #ty_generics #where_clause { | ||
const COLUMN_NAMES: &'static [&'static str] = #column_names; | ||
} | ||
}; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pub(crate)
(and all below). It seems this subcrate doesn't use https://github.com/ClickHouse/clickhouse-rs/blob/main/Cargo.toml#L17