mod generate;
mod graph;
mod parse;
use std::collections::HashMap;
use petgraph::{
algo::toposort,
graph::{DiGraph, NodeIndex},
Direction,
};
use proc_macro::TokenStream;
use syn::{parse_macro_input, ExprStruct, Ident, Path, Type};
pub(crate) fn expand(input: TokenStream) -> TokenStream {
let definition = parse_macro_input!(input as ComponentDefinition);
let graph = definition.into();
generate::generate_module(&graph).into()
}
#[derive(Debug)]
struct ComponentDefinition {
name: Ident,
input_schema: InputSchema,
components: Vec<ComponentInstance>,
}
struct ComponentGraph {
definition: ComponentDefinition,
dependencies: DiGraph<usize, graph::Connection>,
}
impl From<ComponentDefinition> for ComponentGraph {
fn from(definition: ComponentDefinition) -> Self {
let dependencies = graph::build_graph(&definition.components);
Self {
definition,
dependencies,
}
}
}
type InputSchema = HashMap<Ident, InputField>;
#[derive(Debug)]
enum InputField {
Type(Type),
Struct(InputSchema),
}
#[derive(Debug)]
struct ComponentInstance {
name: Ident,
module: Path,
input_struct: ExprStruct,
}
impl ComponentGraph {
pub fn is_used_as_input(&self, component_index: usize) -> bool {
let node_index = NodeIndex::new(component_index);
self.dependencies
.neighbors_directed(node_index, Direction::Outgoing)
.next()
.is_some()
}
pub fn call_order(&self) -> Vec<usize> {
toposort(&self.dependencies, None)
.expect("Cycle detected in component dependencies")
.into_iter()
.map(|node_index| self.dependencies[node_index])
.collect()
}
}