#![allow(warnings)]
use injectable_rs_graph::{DependencyGraph, GraphNode, ValidationError};
fn main() {
println!("=== Dependency Graph Validation Example ===\n");
println!("1. Valid dependency chain:");
let graph = DependencyGraph::new(vec![
GraphNode::new("UserService", &["Database", "Cache"]),
GraphNode::new("Database", &["Config"]),
GraphNode::new("Cache", &["Config"]),
GraphNode::leaf("Config"),
]);
match graph.validate() {
Ok(()) => println!(" Graph is valid!\n"),
Err(errors) => println!(" Errors: {errors:?}\n"),
}
let topo = graph
.topological_order()
.expect("should have topological order");
println!(" Topological order: {topo:?}");
println!(" (Config before Database/Cache, Database/Cache before UserService)\n");
let destruction = graph
.destruction_order()
.expect("should have destruction order");
println!(" Destruction order: {destruction:?}");
println!(" (UserService before Database/Cache, Database/Cache before Config)\n");
println!("2. Circular dependency detection:");
let graph = DependencyGraph::new(vec![
GraphNode::new("UserService", &["AuthService"]),
GraphNode::new("AuthService", &["SessionManager"]),
GraphNode::new("SessionManager", &["UserService"]),
]);
match graph.validate() {
Ok(()) => println!(" Graph is valid (unexpected!)\n"),
Err(errors) => {
for err in &errors {
if let ValidationError::CircularDependency { chain } = err {
println!(" Circular dependency detected: {}", chain.join(" -> "));
}
}
println!();
}
}
println!("3. Missing dependency detection:");
let graph = DependencyGraph::new(vec![
GraphNode::new("UserService", &["Database", "Cache"]),
GraphNode::leaf("Database"),
]);
match graph.validate() {
Ok(()) => println!(" Graph is valid (unexpected!)\n"),
Err(errors) => {
for err in &errors {
if let ValidationError::MissingDependency { source, missing } = err {
println!(
" Missing dependency: '{source}' depends on '{missing}' which is not in the graph"
);
}
}
println!();
}
}
println!("4. Scope validation:");
let graph = DependencyGraph::new(vec![
GraphNode::with_scope("UserService", &["Database"], "singleton"),
GraphNode::leaf_with_scope("Database", "singleton"),
]);
println!(
" singleton -> singleton: {}",
if graph.validate().is_ok() {
"OK"
} else {
"INVALID"
}
);
let graph = DependencyGraph::new(vec![
GraphNode::with_scope("RequestHandler", &["Database"], "transient"),
GraphNode::leaf_with_scope("Database", "singleton"),
]);
println!(
" transient -> singleton: {}",
if graph.validate().is_ok() {
"OK"
} else {
"INVALID"
}
);
let graph = DependencyGraph::new(vec![
GraphNode::with_scope("HandlerA", &["HandlerB"], "transient"),
GraphNode::leaf_with_scope("HandlerB", "transient"),
]);
println!(
" transient -> transient: {}",
if graph.validate().is_ok() {
"OK"
} else {
"INVALID"
}
);
let graph = DependencyGraph::new(vec![
GraphNode::with_scope("SingletonService", &["TransientHandler"], "singleton"),
GraphNode::leaf_with_scope("TransientHandler", "transient"),
]);
match graph.validate() {
Ok(()) => println!(" singleton -> transient: OK (unexpected!)"),
Err(errors) => {
for err in &errors {
if let ValidationError::ScopeMismatch {
source,
source_scope,
dependency,
dependency_scope,
} = err
{
println!(" singleton -> transient: INVALID");
println!(
" '{source}' ({source_scope}) cannot depend on '{dependency}' ({dependency_scope})"
);
println!(" Reason: wider-scope type would capture narrower-scope instance");
}
}
}
}
println!();
println!("5. Diamond dependency (valid):");
let graph = DependencyGraph::new(vec![
GraphNode::new("App", &["ServiceA", "ServiceB"]),
GraphNode::new("ServiceA", &["Database"]),
GraphNode::new("ServiceB", &["Database"]),
GraphNode::leaf("Database"),
]);
match graph.validate() {
Ok(()) => println!(" Diamond graph is valid!\n"),
Err(errors) => println!(" Errors: {errors:?}\n"),
}
let topo = graph.topological_order().expect("should have order");
println!(" Topological order: {topo:?}\n");
println!("6. Mixed scope validation (diamond with scope errors):");
let graph = DependencyGraph::new(vec![
GraphNode::with_scope("SingletonApp", &["SingletonB", "TransientC"], "singleton"),
GraphNode::with_scope("SingletonB", &["TransientD"], "singleton"),
GraphNode::leaf_with_scope("TransientC", "transient"),
GraphNode::leaf_with_scope("TransientD", "transient"),
]);
match graph.validate() {
Ok(()) => println!(" Graph is valid (unexpected!)\n"),
Err(errors) => {
println!(" Found {} error(s):", errors.len());
for err in &errors {
if let ValidationError::ScopeMismatch {
source,
source_scope,
dependency,
dependency_scope,
} = err
{
println!(" {source} ({source_scope}) -> {dependency} ({dependency_scope})");
}
}
println!();
}
}
println!("=== Example Complete ===");
}