getter 0.2.0

生成get方法
Documentation
//! # 通过派生宏`#[derive(Getter)]`为结构体字段生成`get`方法,字段可附加`#[get]`属性
//!
//! > + 结构体只能是named struct
//! > + 方法名为字段名
//!
//! `get`属性可选值
//!
//! + skip:bool类型,为true时,不为该字段生成`get`方法
//! + pri:   bool类型,为true时,为该字段生成私有方法
//! + default:  表达式,字段为非[Option]类型或[Option]泛型不是进本数据类型和[String]类型会忽略该字段
//!
//! ## 说明
//!
//! ### 字段为非`Option`类型
//!
//! + 字段类型为`基本数据类型`,则方法返回`基本数据类型`
//! + 字段类型为`String`类型,则方法返回`&str`类型
//! + 字段类型为`其它类型则`,则方法返回`其它类型则`的引用
//!
//! ###  字段为`Option`类型
//!
//! + 字段包裹类型为`基本数据类型`,则方法返回`基本数据类型`
//! + 字段包裹类型为`String`类型,则方法返回`&str`类型
//! + 字段包裹类型为`其它类型`,则方法返回`Option`类型
//! 
//! > 字段上没有`#[get]`属性,则生成公有方法
//! ## 示例
//!
//! 源代码
//!
//! ```rust
//! #[derive(Debug, Getter)]
//! struct GetterExample {
//!     #[get(default = 1)]
//!     age: Option<u8>,
//!     name: String,
//!     #[get(default = "tom")]
//!     nick_name: Option<String>,
//!     #[get(pri)]
//!     counter: Option<u32>,
//!     #[get(skip)]
//!     skip: bool,
//!     protocol: Protocol,
//!     protocol_option: Option<Protocol>,
//! }
//! #[derive(Debug, Clone, Copy)]
//! pub enum Protocol {
//!     Mysql,
//!     Postgres,
//!     Sqlite,
//! }
//!
//! impl Default for Protocol {
//!     fn default() -> Self {
//!         Protocol::Mysql
//!     }
//! }
//! ```
//!
//! 宏展开后的代码
//!
//! ```rust
//! impl GetterExample {
//!     #[inline(always)]
//!     pub fn age(&self) -> u8 { self.age.unwrap_or(1) }
//!     #[inline(always)]
//!     pub fn name(&self) -> &str { &self.name }
//!     #[inline(always)]
//!     pub fn nick_name(&self) -> &str { &self.nick_name.as_deref().unwrap_or("tom") }
//!     #[inline(always)]
//!     fn counter(&self) -> u32 { self.counter.unwrap_or_default() }
//!     #[inline(always)]
//!     pub fn protocol(&self) -> &Protocol { &self.protocol }
//!     #[inline(always)]
//!     pub fn protocol_option(&self) -> &Option<Protocol> { &self.protocol_option }
//! }
//! ```

use darling::{Error, FromDeriveInput, FromField, FromMeta};
use proc_macro::TokenStream;
use proc_macro2::TokenStream as TokenStream2;
use proc_macro_error2::{abort_call_site, proc_macro_error};
use quote::quote;
use syn::{parse_macro_input, parse_str, DeriveInput, GenericArgument, Meta, PathArguments, Type, TypePath};

mod generate;

#[proc_macro_derive(Getter, attributes(get))]
#[proc_macro_error]
pub fn getter(input: TokenStream) -> TokenStream {
    let ast = parse_macro_input!(input as DeriveInput);
    let result = Getter::from_derive_input(&ast);
    let mut getter = match result {
        Ok(input) => input,
        Err(e) => return Error::custom(e).write_errors().into(),
    };
    // println!("getter:{getter:?}");
    expand(&mut getter).into()
}

fn expand(getter: &mut Getter) -> TokenStream2 {
    let name = &getter.ident;
    let generics = &getter.generics;
    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();

    // Is it a struct?
    if let darling::ast::Data::Struct(ref mut fields) = getter.data {
        let generated = fields.fields
            .iter_mut()
            .map(|f| {
                let field_ty = &f.ty;
                let inner_type = extract_option_inner_type(&field_ty);
                match inner_type {
                    Some(ref ty) => {
                        let is_option = true;
                        let primitive = primitives().contains(ty);
                        let string = string().eq(ty);
                        f.is_option = is_option;
                        f.is_primitive = primitive;
                        f.is_string = string;
                    },
                    None => {
                        let is_option = false;
                        let primitive = primitives().contains(field_ty);
                        let string = string().eq(field_ty);
                        f.is_option = is_option;
                        f.is_primitive = primitive;
                        f.is_string = string;
                    }
                }
                f.inner_type = inner_type;
                f
            })
            // .filter(|f| !f.is_option || (f.is_string || f.is_primitive))
            .filter(|f| !f.skip)
            .map(|f| generate::implement(f));
        quote! {
            impl #impl_generics #name #ty_generics #where_clause {
                #(#generated)*
            }
        }
    } else {
        // Nope. This is an Enum. We cannot handle these!
        abort_call_site!("#[derive(Getters)]只能定义在结构体上");
    }
}


/// 如果是[Option],则提取内部类型
fn extract_option_inner_type(ty: &Type) -> Option<Type> {
    if let Type::Path(type_path) = ty {
        // 获取类型路径的最后一个段
        let segment = type_path.path.segments.last()?;

        // 检查标识符是否为 "Option"
        if segment.ident == "Option" {
            // 提取泛型参数
            if let PathArguments::AngleBracketed(args) = &segment.arguments {
                if let Some(GenericArgument::Type(inner_ty)) = args.args.first() {
                    return Some(inner_ty.clone());
                }
            }
        }
    }
    None
}
/// 基本数据类型
fn primitives() -> [Type; 16] {
    [
        Type::Path(create_type_path("i8")),
        Type::Path(create_type_path("i16")),
        Type::Path(create_type_path("i32")),
        Type::Path(create_type_path("i64")),
        Type::Path(create_type_path("i128")),
        Type::Path(create_type_path("u8")),
        Type::Path(create_type_path("u16")),
        Type::Path(create_type_path("u32")),
        Type::Path(create_type_path("u64")),
        Type::Path(create_type_path("u128")),
        Type::Path(create_type_path("isize")),
        Type::Path(create_type_path("usize")),
        Type::Path(create_type_path("bool")),
        Type::Path(create_type_path("char")),
        Type::Path(create_type_path("f32")),
        Type::Path(create_type_path("f64")),
    ]
}

/// String类型
fn string() -> Type {
    Type::Path(create_type_path("String"))
}

/// 创建一个类型
fn create_type_path(path: &str) -> TypePath {
    let result = parse_str::<TypePath>(path);

    match result {
        Ok(ty) => ty,
        Err(_) => abort_call_site!("类型解析失败"),
    }
}

// 派生宏的输入结构
#[derive(Debug, FromDeriveInput)]
#[darling(attributes(get), supports(struct_named))]
struct Getter {
    pub ident: syn::Ident,
    pub generics: syn::Generics,
    pub data: darling::ast::Data<(), GetterField>,
}

// 完整的 GetterOptions
#[derive(Debug, Clone, FromField)]
#[darling(attributes(get))]
struct GetterField {
    pub ident: Option<syn::Ident>,
    pub ty: Type,

    /// 是否跳过该字段
    #[darling(default)]
    pub skip: bool,
    /// 生成的方法是否是私有方法
    #[darling(default)]
    pub pri: bool,
    /// 当字段为[Option]类型且为[None]时指定默认值
    pub default: Option<DefaultValue>,
    #[darling(skip, default)]
    pub is_option: bool,
    #[darling(skip, default)]
    pub inner_type: Option<Type>,
    #[darling(skip, default)]
    pub is_string: bool,
    #[darling(skip, default)]
    pub is_primitive: bool,

}

// 自定义 Default 的解析:支持无值(default)和有值(default = expr)
#[derive(Debug, Clone)]
enum DefaultValue {
    NoValue,          // 对应 `default`
    Value(syn::Expr), // 对应 `default = expr`
}

impl Default for DefaultValue {
    fn default() -> Self {
        DefaultValue::NoValue
    }
}

impl FromMeta for DefaultValue {
    fn from_meta(meta: &Meta) -> darling::Result<Self> {
        match meta {
            Meta::Path(_) => {
                // 单独的 `default`(无值)
                Ok(DefaultValue::NoValue)
            }
            Meta::NameValue(mnv) => {
                // `default = expr`
                Ok(DefaultValue::Value(mnv.value.clone()))
            }
            Meta::List(_) => Err(Error::unsupported_format("list")),
        }
    }
}