//! Example of Higher-Order Topologies in Harmony. //! Demonstrates how `FailoverTopology` automatically provides failover for *any* capability //! supported by a sub-topology `T` via blanket trait impls. //! //! Key insight: No manual impls per T or capability -- scales effortlessly. //! Users can: //! - Write new `Topology` (impl capabilities on a struct). //! - Compose with `FailoverTopology` (gets capabilities if T has them). //! - Compile fails if capability missing (safety). use async_trait::async_trait; use tokio; /// Capability trait: Deploy and manage PostgreSQL. #[async_trait] pub trait PostgreSQL { async fn deploy(&self, config: &PostgreSQLConfig) -> Result; async fn get_replication_certs(&self, cluster_name: &str) -> Result; } /// Capability trait: Deploy Docker. #[async_trait] pub trait Docker { async fn deploy_docker(&self) -> Result; } /// Configuration for PostgreSQL deployments. #[derive(Clone)] pub struct PostgreSQLConfig; /// Replication certificates. #[derive(Clone)] pub struct ReplicationCerts; /// Concrete topology: Kubernetes Anywhere (supports PostgreSQL). #[derive(Clone)] pub struct K8sAnywhereTopology; #[async_trait] impl PostgreSQL for K8sAnywhereTopology { async fn deploy(&self, _config: &PostgreSQLConfig) -> Result { // Real impl: Use k8s helm chart, operator, etc. Ok("K8sAnywhere PostgreSQL deployed".to_string()) } async fn get_replication_certs(&self, _cluster_name: &str) -> Result { Ok(ReplicationCerts) } } /// Concrete topology: Linux Host (supports Docker). #[derive(Clone)] pub struct LinuxHostTopology; #[async_trait] impl Docker for LinuxHostTopology { async fn deploy_docker(&self) -> Result { // Real impl: Install/configure Docker on host. Ok("LinuxHost Docker deployed".to_string()) } } /// Higher-Order Topology: Composes multiple sub-topologies (primary + replica). /// Automatically derives *all* capabilities of `T` with failover orchestration. /// /// - If `T: PostgreSQL`, then `FailoverTopology: PostgreSQL` (blanket impl). /// - Same for `Docker`, etc. No boilerplate! /// - Compile-time safe: Missing `T: Capability` → error. #[derive(Clone)] pub struct FailoverTopology { /// Primary sub-topology. pub primary: T, /// Replica sub-topology. pub replica: T, } /// Blanket impl: Failover PostgreSQL if T provides PostgreSQL. /// Delegates reads to primary; deploys to both. #[async_trait] impl PostgreSQL for FailoverTopology { async fn deploy(&self, config: &PostgreSQLConfig) -> Result { // Orchestrate: Deploy primary first, then replica (e.g., via pg_basebackup). let primary_result = self.primary.deploy(config).await?; let replica_result = self.replica.deploy(config).await?; Ok(format!("Failover PG deployed: {} | {}", primary_result, replica_result)) } async fn get_replication_certs(&self, cluster_name: &str) -> Result { // Delegate to primary (replica follows). self.primary.get_replication_certs(cluster_name).await } } /// Blanket impl: Failover Docker if T provides Docker. #[async_trait] impl Docker for FailoverTopology { async fn deploy_docker(&self) -> Result { // Orchestrate across primary + replica. let primary_result = self.primary.deploy_docker().await?; let replica_result = self.replica.deploy_docker().await?; Ok(format!("Failover Docker deployed: {} | {}", primary_result, replica_result)) } } #[tokio::main] async fn main() { let config = PostgreSQLConfig; println!("=== ✅ PostgreSQL Failover (K8sAnywhere supports PG) ==="); let pg_failover = FailoverTopology { primary: K8sAnywhereTopology, replica: K8sAnywhereTopology, }; let result = pg_failover.deploy(&config).await.unwrap(); println!("Result: {}", result); println!("\n=== ✅ Docker Failover (LinuxHost supports Docker) ==="); let docker_failover = FailoverTopology { primary: LinuxHostTopology, replica: LinuxHostTopology, }; let result = docker_failover.deploy_docker().await.unwrap(); println!("Result: {}", result); println!("\n=== ❌ Would fail to compile (K8sAnywhere !: Docker) ==="); // let invalid = FailoverTopology { // primary: K8sAnywhereTopology, // replica: K8sAnywhereTopology, // }; // invalid.deploy_docker().await.unwrap(); // Error: `K8sAnywhereTopology: Docker` not satisfied! // Very clear error message : // error[E0599]: the method `deploy_docker` exists for struct `FailoverTopology`, but its trait bounds were not satisfied // --> src/main.rs:90:9 // | // 4 | pub struct FailoverTopology { // | ------------------------------ method `deploy_docker` not found for this struct because it doesn't satisfy `FailoverTopology: Docker` // ... // 37 | struct K8sAnywhereTopology; // | -------------------------- doesn't satisfy `K8sAnywhereTopology: Docker` // ... // 90 | invalid.deploy_docker(); // `T: Docker` bound unsatisfied // | ^^^^^^^^^^^^^ method cannot be called on `FailoverTopology` due to unsatisfied trait bounds // | // note: trait bound `K8sAnywhereTopology: Docker` was not satisfied // --> src/main.rs:61:9 // | // 61 | impl Docker for FailoverTopology { // | ^^^^^^ ------ ------------------- // | | // | unsatisfied trait bound introduced here // note: the trait `Docker` must be implemented }