use proc_macro2::{Ident, TokenStream};
use quote::quote;
use crate::derive::data_models::{CStyleEnum, ConvertType, GodotConvert, NewtypeStruct, ViaType};
use crate::derive::derive_godot_convert::EnumeratorExprCache;
pub fn make_togodot(convert: &GodotConvert, cache: &mut EnumeratorExprCache) -> TokenStream {
let GodotConvert {
ty_name: name,
convert_type: data,
} = convert;
match data {
ConvertType::NewType { field } => make_togodot_for_newtype_struct(name, field),
ConvertType::Enum {
variants,
via: ViaType::GString { .. },
} => make_togodot_for_string_enum(name, variants),
ConvertType::Enum {
variants,
via: ViaType::Int { int_ident },
} => make_togodot_for_int_enum(name, variants, int_ident, cache),
}
}
fn make_togodot_for_newtype_struct(name: &Ident, field: &NewtypeStruct) -> TokenStream {
let field_name = field.field_name();
let via_type = &field.ty;
quote! {
impl ::godot::meta::ToGodot for #name {
type Pass = <#via_type as ::godot::meta::ToGodot>::Pass;
fn to_godot(&self) -> ::godot::meta::ToArg<'_, Self::Via, Self::Pass> {
::godot::meta::ToGodot::to_godot(&self.#field_name)
}
}
}
}
fn make_togodot_for_int_enum(
name: &Ident,
enum_: &CStyleEnum,
int: &Ident,
cache: &mut EnumeratorExprCache,
) -> TokenStream {
let discriminants =
cache.map_ord_exprs(int, enum_.enumerator_names(), enum_.enumerator_ord_exprs());
let names = enum_.enumerator_names();
quote! {
impl ::godot::meta::ToGodot for #name {
type Pass = ::godot::meta::conv::ByValue;
#[allow(unused_parens)] fn to_godot(&self) -> Self::Via {
match self {
#(
#name::#names => #discriminants,
)*
}
}
}
}
}
fn make_togodot_for_string_enum(name: &Ident, enum_: &CStyleEnum) -> TokenStream {
let names = enum_.enumerator_names();
let names_str = names.iter().map(ToString::to_string).collect::<Vec<_>>();
quote! {
impl ::godot::meta::ToGodot for #name {
type Pass = ::godot::meta::conv::ByValue;
fn to_godot(&self) -> Self::Via {
match self {
#(
#name::#names => #names_str.into(),
)*
}
}
}
}
}