use proc_macro2::{Ident, TokenStream};
use quote::ToTokens;
use super::c_style_enum::CStyleEnum;
use super::godot_attribute::{GodotAttribute, ViaType};
use super::newtype::NewtypeStruct;
use crate::ParseResult;
use crate::util::bail;
pub struct GodotConvert {
pub ty_name: Ident,
pub convert_type: ConvertType,
}
impl GodotConvert {
pub fn parse_declaration(item: venial::Item) -> ParseResult<Self> {
let (name, where_clause, generic_params) = match &item {
venial::Item::Struct(struct_) => (
struct_.name.clone(),
&struct_.where_clause,
&struct_.generic_params,
),
venial::Item::Enum(enum_) => (
enum_.name.clone(),
&enum_.where_clause,
&enum_.generic_params,
),
other => {
return bail!(
other,
"#[derive(GodotConvert)] only supports structs and enums"
);
}
};
if let Some(generic_params) = generic_params {
return bail!(
generic_params,
"#[derive(GodotConvert)] does not support lifetimes or generic parameters"
);
}
if let Some(where_clause) = where_clause {
return bail!(
where_clause,
"#[derive(GodotConvert)] does not support where clauses"
);
}
let data = ConvertType::parse_declaration(item)?;
Ok(Self {
ty_name: name,
convert_type: data,
})
}
}
pub enum ConvertType {
NewType { field: NewtypeStruct },
Enum { variants: CStyleEnum, via: ViaType },
}
impl ConvertType {
pub fn parse_declaration(item: venial::Item) -> ParseResult<Self> {
let attribute = GodotAttribute::parse_attribute(&item)?;
match &item {
venial::Item::Struct(struct_) => {
let GodotAttribute::Transparent { .. } = attribute else {
return bail!(
attribute.span(),
"#[derive(GodotConvert)] on structs currently only works with #[godot(transparent)]"
);
};
Ok(Self::NewType {
field: NewtypeStruct::parse_struct(struct_)?,
})
}
venial::Item::Enum(enum_) => {
let GodotAttribute::Via { via_type, .. } = attribute else {
return bail!(
attribute.span(),
"#[derive(GodotConvert)] on enums requires #[godot(via = ...)]"
);
};
Ok(Self::Enum {
variants: CStyleEnum::parse_enum(enum_)?,
via: via_type,
})
}
_ => unreachable!(), }
}
pub fn via_type(&self) -> TokenStream {
match self {
ConvertType::NewType { field } => field.ty.to_token_stream(),
ConvertType::Enum { via, .. } => via.to_token_stream(),
}
}
}