use proc_macro2::{Ident, Literal, TokenStream};
use quote::{ToTokens, quote};
use crate::models::domain::TyName;
use crate::util::ident;
pub struct Enum {
pub name: Ident,
pub godot_name: String,
pub surrounding_class: Option<TyName>,
pub is_bitfield: bool,
pub is_private: bool,
pub is_exhaustive: bool,
pub enumerators: Vec<Enumerator>,
pub max_index: Option<usize>,
}
impl Enum {
pub fn derives(&self) -> Vec<Ident> {
let mut derives = vec!["Copy", "Clone", "Eq", "PartialEq", "Hash"];
if self.is_bitfield {
derives.push("Default");
}
derives.into_iter().map(ident).collect()
}
pub fn ord_type(&self) -> Ident {
if self.is_bitfield {
ident("u64")
} else {
ident("i32")
}
}
pub fn unique_ords(&self) -> Option<Vec<i32>> {
let mut unique_ords = self
.enumerators
.iter()
.map(|enumerator| enumerator.value.as_enum_ord())
.collect::<Option<Vec<i32>>>()?;
unique_ords.sort();
unique_ords.dedup();
Some(unique_ords)
}
pub fn engine_trait(&self) -> TokenStream {
if self.is_bitfield {
quote! { crate::obj::EngineBitfield }
} else {
quote! { crate::obj::EngineEnum }
}
}
pub fn find_index_enum_max_impl(
is_bitfield: bool,
enumerators: &[Enumerator],
) -> Option<usize> {
if is_bitfield {
return None;
}
let enumerators = {
let mut enumerators = enumerators.to_vec();
enumerators.sort_by_key(|v| v.value.to_i64());
enumerators
};
let last = enumerators.last()?; if !last.godot_name.ends_with("_MAX") {
return None;
}
let mut last_value = 0;
for enumerator in enumerators.iter() {
let current_value = enumerator.value.to_i64();
if current_value != last_value && current_value != last_value + 1 {
return None;
}
last_value = current_value;
}
Some(last_value as usize)
}
}
#[derive(Clone)]
pub struct Enumerator {
pub name: Ident,
pub godot_name: String,
pub value: EnumeratorValue,
}
#[derive(Clone, Eq, PartialEq, Hash)]
pub enum EnumeratorValue {
Enum(i32),
Bitfield(u64),
}
impl EnumeratorValue {
fn as_enum_ord(&self) -> Option<i32> {
match self {
EnumeratorValue::Enum(i) => Some(*i),
EnumeratorValue::Bitfield(_) => None,
}
}
pub fn to_i64(&self) -> i64 {
match self {
EnumeratorValue::Enum(i) => *i as i64,
EnumeratorValue::Bitfield(i) => *i as i64,
}
}
pub fn unsuffixed_lit(&self) -> Literal {
Literal::i64_unsuffixed(self.to_i64())
}
}
impl ToTokens for EnumeratorValue {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
EnumeratorValue::Enum(i) => i.to_tokens(tokens),
EnumeratorValue::Bitfield(i) => i.to_tokens(tokens),
}
}
}