//! Run with: cargo run --example printer_polymorphism //! //! Demonstrates the trait+enum pattern that stands in for inheritance: //! - `connect()` is called the same way regardless of vendor (polymorphism), //! but each variant's `impl GenericPrinter` runs completely different //! code (override). //! - `dispatch_gcode()` only exists on `BambuPrinter` (extension) — you //! have to `match` the enum back down to the concrete type to reach it, //! which is the trade-off for not having implicit downcasting. use continuum_proxy::printer::{ BambuPrinter, BambuTls, GenericPrinter, KlipperPrinter, PrinterHandle, PrusaLinkPrinter, PrusaSerialPrinter, }; #[tokio::main] async fn main() { let mut fleet: Vec = vec![ PrinterHandle::BambuV1(BambuPrinter::new("p1", "P1S", "192.168.1.49", "87654321", BambuTls::BundledCa)), PrinterHandle::BambuV2(BambuPrinter::new("p2", "X1 Carbon", "192.168.1.50", "12345678", BambuTls::BundledCa)), PrinterHandle::PrusaLink(PrusaLinkPrinter::new("p3", "MK4", "192.168.1.51", "prusa-api-key")), PrinterHandle::PrusaSerial(PrusaSerialPrinter::new("p4", "MK3S+", 0)), PrinterHandle::Klipper(KlipperPrinter::new("p5", "Voron 2.4", "192.168.1.52")), // No host configured — this one will hit the Err path. PrinterHandle::Klipper(KlipperPrinter::new("p6", "Broken Voron", "")), ]; // Uniform call site: every printer connects the same way from the // caller's point of view, even though each variant's `connect()` body // is an unrelated implementation. for printer in &mut fleet { match printer.connect().await { Ok(()) => println!(" -> connected: {}\n", printer.display_name()), Err(err) => println!(" -> failed: {err}\n"), } } // Vendor-only extension: reachable only after matching the concrete // variant back out of the enum. Both Bambu variants wrap the same // BambuPrinter struct right now, so both get dispatch_gcode(). for printer in &fleet { if let PrinterHandle::BambuV1(bambu) | PrinterHandle::BambuV2(bambu) = printer { bambu.dispatch_gcode("part.gcode.3mf"); } } }