use std::collections::HashMap;
use std::collections::HashSet;
use crate::passes::dependency_analysis::DependencyGraph;
use crate::types::cooked::Definition;
use heck::ToPascalCase;
use quote::quote;
use quote::ToTokens;
use quote::TokenStreamExt;
#[derive(Clone, Copy, Debug)]
pub struct Type<'a> {
pub name: &'a str,
pub needs_lifetime: bool,
}
impl ToTokens for Type<'_> {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
tokens.append_all(self.to_token_stream())
}
fn to_token_stream(&self) -> proc_macro2::TokenStream {
let name = quote::format_ident!("{}", self.name.to_pascal_case());
let lifetime = self.needs_lifetime.then(|| quote!(<'a>));
quote!(#name #lifetime)
}
}
pub fn resolve_types<'a>(
definitions: &'a HashSet<Definition<'a>>,
graph: &DependencyGraph<'a>,
overrides: &HashMap<&'a str, Type<'a>>,
) -> HashMap<&'a str, Type<'a>> {
let mut types: HashMap<&str, Type> = HashMap::new();
for id in graph.bottom_up() {
let ty = if let Some(ty) = overrides.get(id) {
*ty
} else {
let definition = definitions.get(id).unwrap();
let name = definition.name();
let needs_lifetime = match definition {
Definition::Amount(_)
| Definition::CodeSet(_)
| Definition::Date(_)
| Definition::DateTime(_)
| Definition::Indicator(_)
| Definition::Month(_)
| Definition::Quantity(_)
| Definition::Rate(_)
| Definition::Time(_)
| Definition::Year(_)
| Definition::YearMonth(_) => false,
Definition::IdentifierSet(_) | Definition::Text(_) => true,
other => other.dependencies().any(|dep| types[dep].needs_lifetime),
};
Type {
name,
needs_lifetime,
}
};
let old = types.insert(id, ty);
assert!(old.is_none());
}
types
}