df-derive-macros 0.3.0

Procedural derive macro implementation for df-derive.
Documentation
use crate::codegen::encoder::idents;
use crate::ir::{DecimalBackend, DisplayBase, LeafSpec, StringyBase, StructIR};
use proc_macro2::TokenStream;
use quote::quote;
use syn::Type;

use super::type_deps::{GenericContext, push_unique_type, type_depends_on_generics};

pub fn generate_eager_asserts(
    ir: &StructIR,
    to_dataframe_trait: &syn::Path,
    columnar_trait: &syn::Path,
    decimal128_encode_trait: &syn::Path,
) -> TokenStream {
    let generic_ctx = GenericContext::new(ir);
    let mut nested_types = Vec::new();
    let mut decimal_backend_types = Vec::new();
    let mut as_ref_str_types = Vec::new();
    let mut display_types = Vec::new();

    for column in &ir.columns {
        let leaf_spec = column.leaf_spec().as_leaf_spec();
        collect_nested_asserts(leaf_spec, &generic_ctx, &mut nested_types);
        collect_decimal_asserts(leaf_spec, &generic_ctx, &mut decimal_backend_types);
        collect_as_ref_str_asserts(leaf_spec, &generic_ctx, &mut as_ref_str_types);
        collect_display_asserts(leaf_spec, &generic_ctx, &mut display_types);
    }

    if nested_types.is_empty()
        && decimal_backend_types.is_empty()
        && as_ref_str_types.is_empty()
        && display_types.is_empty()
    {
        return TokenStream::new();
    }

    let nested_asserts = if nested_types.is_empty() {
        TokenStream::new()
    } else {
        let assert_nested_traits = idents::nested_traits_assert_helper();
        quote! {
            const fn #assert_nested_traits<
                __DfDeriveT: #to_dataframe_trait + #columnar_trait
            >() {}

            #(
                #assert_nested_traits::<#nested_types>();
            )*
        }
    };
    let decimal_backend_asserts = if decimal_backend_types.is_empty() {
        TokenStream::new()
    } else {
        let assert_decimal_backend = idents::decimal_backend_assert_helper();
        quote! {
            const fn #assert_decimal_backend<
                __DfDeriveT: #decimal128_encode_trait
            >() {}

            #(
                #assert_decimal_backend::<#decimal_backend_types>();
            )*
        }
    };
    let as_ref_str_asserts = if as_ref_str_types.is_empty() {
        TokenStream::new()
    } else {
        let assert_as_ref_str = idents::as_ref_str_assert_helper();
        quote! {
            const fn #assert_as_ref_str<
                __DfDeriveT: ?::core::marker::Sized + ::core::convert::AsRef<str>
            >() {}

            #(
                #assert_as_ref_str::<#as_ref_str_types>();
            )*
        }
    };
    let display_asserts = if display_types.is_empty() {
        TokenStream::new()
    } else {
        let assert_display = idents::display_assert_helper();
        quote! {
            const fn #assert_display<
                __DfDeriveT: ?::core::marker::Sized + ::core::fmt::Display
            >() {}

            #(
                #assert_display::<#display_types>();
            )*
        }
    };

    quote! {
        #nested_asserts
        #decimal_backend_asserts
        #as_ref_str_asserts
        #display_asserts
    }
}

fn collect_decimal_asserts(leaf: &LeafSpec, generic_ctx: &GenericContext, out: &mut Vec<Type>) {
    leaf.walk_terminal_leaves(&mut |leaf| {
        if let LeafSpec::Decimal {
            backend: DecimalBackend::Struct(ty),
            ..
        } = leaf
            && !type_depends_on_generics(ty, generic_ctx)
        {
            push_unique_type(out, ty);
        }
    });
}

fn collect_nested_asserts(leaf: &LeafSpec, generic_ctx: &GenericContext, out: &mut Vec<Type>) {
    leaf.walk_terminal_leaves(&mut |leaf| {
        if let LeafSpec::Struct(ty) = leaf
            && !type_depends_on_generics(ty, generic_ctx)
        {
            push_unique_type(out, ty);
        }
    });
}

fn collect_as_ref_str_asserts(leaf: &LeafSpec, generic_ctx: &GenericContext, out: &mut Vec<Type>) {
    leaf.walk_terminal_leaves(&mut |leaf| {
        if let LeafSpec::AsStr(StringyBase::Struct(ty)) = leaf
            && !type_depends_on_generics(ty, generic_ctx)
        {
            push_unique_type(out, ty);
        }
    });
}

fn collect_display_asserts(leaf: &LeafSpec, generic_ctx: &GenericContext, out: &mut Vec<Type>) {
    leaf.walk_terminal_leaves(&mut |leaf| {
        if let LeafSpec::AsString(DisplayBase::Struct(ty)) = leaf
            && !type_depends_on_generics(ty, generic_ctx)
        {
            push_unique_type(out, ty);
        }
    });
}