use proc_macro_crate::{FoundCrate, crate_name};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::DeriveInput;
use crate::attrs;
use super::external_paths;
pub struct RuntimeTraitPaths {
pub to_dataframe: syn::Path,
pub columnar: syn::Path,
pub decimal128_encode: syn::Path,
}
#[allow(clippy::struct_field_names)]
pub struct MacroConfig {
pub traits: RuntimeTraitPaths,
pub external_paths: external_paths::ExternalPaths,
}
fn resolve_dataframe_mod_for_crate(name: &str, lib_crate_name: &str) -> Option<TokenStream> {
match crate_name(name) {
Ok(FoundCrate::Name(resolved)) => {
let ident = format_ident!("{}", resolved);
Some(quote! { ::#ident::dataframe })
}
Ok(FoundCrate::Itself) if is_expanding_lib_target(lib_crate_name) => {
Some(quote! { crate::dataframe })
}
Ok(FoundCrate::Itself) => {
let ident = format_ident!("{}", lib_crate_name);
Some(quote! { ::#ident::dataframe })
}
Err(_) => None,
}
}
fn is_expanding_lib_target(lib_crate_name: &str) -> bool {
std::env::var("CARGO_CRATE_NAME").as_deref() == Ok(lib_crate_name)
}
pub fn resolve_default_dataframe_mod() -> TokenStream {
resolve_dataframe_mod_for_crate("df-derive", "df_derive")
.or_else(|| resolve_dataframe_mod_for_crate("df-derive-core", "df_derive_core"))
.or_else(|| resolve_dataframe_mod_for_crate("paft-utils", "paft_utils"))
.or_else(|| resolve_dataframe_mod_for_crate("paft", "paft"))
.unwrap_or_else(|| quote! { crate::core::dataframe })
}
pub fn build_macro_config(ast: &DeriveInput) -> syn::Result<MacroConfig> {
let default_df_mod = resolve_default_dataframe_mod();
let attrs = attrs::parse_container_attrs(ast)?;
let uses_default_dataframe_runtime = attrs.to_dataframe.is_none() && attrs.columnar.is_none();
let explicit_default_dataframe_mod = attrs::explicit_builtin_default_dataframe_mod(
attrs.to_dataframe.as_ref(),
attrs.columnar.as_ref(),
);
let to_dataframe = attrs.to_dataframe.as_ref().map_or_else(
|| attrs::runtime_trait_path(&default_df_mod, "ToDataFrame"),
|override_| override_.value.clone(),
);
let columnar = match (&attrs.columnar, &attrs.to_dataframe) {
(Some(override_), _) => override_.value.clone(),
(None, Some(override_)) => attrs::rebase_last_segment(&override_.value, "Columnar"),
(None, None) => attrs::runtime_trait_path(&default_df_mod, "Columnar"),
};
let decimal128_encode = match (&attrs.decimal128_encode, &attrs.to_dataframe) {
(Some(override_), _) => override_.value.clone(),
(None, Some(override_)) => attrs::rebase_last_segment(&override_.value, "Decimal128Encode"),
(None, None) => attrs::runtime_trait_path(&default_df_mod, "Decimal128Encode"),
};
let external_paths = explicit_default_dataframe_mod.as_ref().map_or_else(
|| {
if uses_default_dataframe_runtime {
external_paths::default_runtime_paths(&default_df_mod)
} else {
external_paths::direct_dependency_paths()
}
},
|dataframe_mod| {
let dataframe_mod = quote! { #dataframe_mod };
external_paths::default_runtime_paths(&dataframe_mod)
},
);
Ok(MacroConfig {
traits: RuntimeTraitPaths {
to_dataframe,
columnar,
decimal128_encode,
},
external_paths,
})
}