use std::collections::HashMap;
use prebindgen_flat::flat::{Flat, TypeRef};
use super::*;
use crate::unfold::{DeconId, DeconSpec, UnfoldPlan};
pub type Crossing = (Direction, TypeKey);
pub trait Conversions<M> {
fn flat(&self) -> &Flat;
fn reading(&self, key: &TypeKey) -> Option<TypeRef>;
fn conversion(&self, dir: Direction, reading: &TypeRef) -> Option<&TypeEntry<M>>;
fn reading_of(&self, ty: &syn::Type) -> Option<TypeRef> {
self.reading(&TypeKey::from_type(ty))
}
fn input_entry(&self, reading: &TypeRef) -> Option<&TypeEntry<M>> {
self.conversion(Direction::Input, reading)
}
fn output_entry(&self, reading: &TypeRef) -> Option<&TypeEntry<M>> {
self.conversion(Direction::Output, reading)
}
fn callback_arg_plan(&self, key: &TypeKey) -> Option<&UnfoldPlan>;
fn callback_arg_plans(&self) -> &HashMap<TypeKey, UnfoldPlan>;
fn unfold_plans(&self) -> &HashMap<syn::Ident, UnfoldPlan>;
fn error_plans(&self) -> &HashMap<syn::Ident, UnfoldPlan>;
fn decon_plans(&self) -> &HashMap<DeconId, DeconSpec>;
fn crossing_keys(&self, dir: Direction) -> Vec<TypeKey>;
fn origin_module(&self, ident: &syn::Ident) -> Option<syn::Path> {
origin_module_of(self.flat(), ident)
}
fn default_module(&self) -> Option<syn::Path> {
default_module_of(self.flat())
}
}
impl<M> Conversions<M> for Building<'_, M> {
fn flat(&self) -> &Flat {
&self.registry.flat
}
fn reading(&self, key: &TypeKey) -> Option<TypeRef> {
self.registry.reading(key)
}
fn conversion(&self, dir: Direction, reading: &TypeRef) -> Option<&TypeEntry<M>> {
self.built.get(&(dir, reading.key()))
}
fn callback_arg_plan(&self, key: &TypeKey) -> Option<&UnfoldPlan> {
self.registry.callback_arg_plans.get(key)
}
fn callback_arg_plans(&self) -> &HashMap<TypeKey, UnfoldPlan> {
&self.registry.callback_arg_plans
}
fn unfold_plans(&self) -> &HashMap<syn::Ident, UnfoldPlan> {
&self.registry.unfold_plans
}
fn error_plans(&self) -> &HashMap<syn::Ident, UnfoldPlan> {
&self.registry.error_plans
}
fn decon_plans(&self) -> &HashMap<DeconId, DeconSpec> {
&self.registry.decon_plans
}
fn crossing_keys(&self, dir: Direction) -> Vec<TypeKey> {
self.all_keys
.iter()
.filter(|(d, _)| *d == dir)
.map(|(_, k)| k.clone())
.collect()
}
}
impl<M> Conversions<M> for Registry<M> {
fn flat(&self) -> &Flat {
&self.flat
}
fn reading(&self, key: &TypeKey) -> Option<TypeRef> {
Registry::reading(self, key)
}
fn conversion(&self, dir: Direction, reading: &TypeRef) -> Option<&TypeEntry<M>> {
self.type_table(dir).get(&reading.key())?.entry.as_ref()
}
fn callback_arg_plan(&self, key: &TypeKey) -> Option<&UnfoldPlan> {
self.callback_arg_plans.get(key)
}
fn callback_arg_plans(&self) -> &HashMap<TypeKey, UnfoldPlan> {
&self.callback_arg_plans
}
fn unfold_plans(&self) -> &HashMap<syn::Ident, UnfoldPlan> {
&self.unfold_plans
}
fn error_plans(&self) -> &HashMap<syn::Ident, UnfoldPlan> {
&self.error_plans
}
fn decon_plans(&self) -> &HashMap<DeconId, DeconSpec> {
&self.decon_plans
}
fn crossing_keys(&self, dir: Direction) -> Vec<TypeKey> {
self.type_table(dir).keys().cloned().collect()
}
}
pub struct Building<'a, M> {
registry: &'a Registry<M>,
built: &'a HashMap<Crossing, TypeEntry<M>>,
all_keys: &'a [Crossing],
}
impl<'a, M> Building<'a, M> {
pub(crate) fn new(
registry: &'a Registry<M>,
built: &'a HashMap<Crossing, TypeEntry<M>>,
all_keys: &'a [Crossing],
) -> Self {
Self {
registry,
built,
all_keys,
}
}
}
pub(super) fn origin_module_of(flat: &Flat, ident: &syn::Ident) -> Option<syn::Path> {
let crate_name = flat.element(ident)?.location().crate_name.as_ref()?;
syn::parse_str(&crate_name.replace('-', "_")).ok()
}
pub(super) fn default_module_of(flat: &Flat) -> Option<syn::Path> {
flat.source_modules()
.first()
.and_then(|m| syn::parse_str(m).ok())
}