Compile the modules once, and clear the warning backlog

`cargo check --all-targets` emitted 32 warnings; it now emits none. Almost all
of them came from one cause: main.rs declared `mod config/fleet/printer/uplink`
while lib.rs declared the same modules, so every file was compiled twice, once
per crate. In the binary copy nothing is externally reachable, so every
`pub use` re-export and every method that only an example or a test calls was
genuinely dead - and the warnings were real about the binary while being wrong
about the library's actual public API. main.rs now uses the library crate and
keeps only `mod go2rtc`, which nothing else needs.

The rest, individually:

- `ModuleInfo` was re-exported from bambu_commands but not from printer, so it
  was unreachable even though `GetVersionResponse.module` is a public field of
  type `Vec<ModuleInfo>` - a caller could not name the type of a field it can
  read. Re-exported rather than dropped.
- Three stub `publish` impls take a payload they do not use yet; renamed to
  `_payload`.
- One unused import in examples/test_bambu_certs.rs.

That leaves the `async_fn_in_trait` lint on GenericPrinter, which is now
`allow`ed with the reasoning written down rather than left to fire on every
build. The old comment said it "only matters once this is wired into the
multi-threaded daemon", which has since happened - so the question got
answered instead of deferred: the futures cannot be required to be `Send`, and
that is fine because every printer is reached through one Arc<Mutex<Vec<..>>>
from the uplink's own task, so they are created and polled in the same place.
The note says what to do if a printer ever gets its own task.

No behaviour change. Tests still pass and the daemon was re-verified against
the live P1P and H2C through the full backend path.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 12:16:48 +00:00
co-authored by Claude Opus 5
parent 8f7a332956
commit 4ab95ff7ce
6 changed files with 37 additions and 21 deletions
+1 -1
View File
@@ -7,7 +7,7 @@
//! this trust question. //! this trust question.
use continuum_proxy::fleet; use continuum_proxy::fleet;
use continuum_proxy::printer::{GenericPrinter, PrinterHandle}; use continuum_proxy::printer::PrinterHandle;
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
let printers = fleet::load(std::path::Path::new("printers.toml"))?; let printers = fleet::load(std::path::Path::new("printers.toml"))?;
+7 -4
View File
@@ -1,7 +1,10 @@
//! Library surface for `continuum-proxy`. The daemon itself is a binary //! Library surface for `continuum-proxy`. The daemon itself is a thin binary
//! (`src/main.rs`); this crate root exists so standalone examples (see //! (`src/main.rs`) that uses this crate; the examples in `examples/` and the
//! `examples/`) and future integration tests can `use continuum_proxy::...` //! integration tests in `tests/` use it too.
//! without duplicating module declarations. //!
//! Everything the daemon needs lives here rather than in the binary, so it is
//! compiled once. `go2rtc` is the one exception: the camera-restreaming
//! watchdog is the daemon's own concern and nothing else calls it.
pub mod config; pub mod config;
pub mod fleet; pub mod fleet;
+9 -6
View File
@@ -1,13 +1,16 @@
mod config; // Everything but go2rtc comes from the library crate (src/lib.rs) rather than
mod fleet; // being re-declared here. Declaring `mod printer;` in both places compiles the
// same files twice, once per crate, and the binary copy warned about every
// `pub use` re-export and every method only examples or tests call - "unused"
// is true inside a binary, where nothing is externally reachable, and wrong
// about the library's actual public API. One copy, no false warnings.
mod go2rtc; mod go2rtc;
mod printer;
mod uplink;
use tracing_subscriber::EnvFilter; use tracing_subscriber::EnvFilter;
use crate::config::Config; use continuum_proxy::config::Config;
use crate::printer::{GenericPrinter, PrinterHandle}; use continuum_proxy::printer::{GenericPrinter, PrinterHandle};
use continuum_proxy::{fleet, uplink};
#[tokio::main] #[tokio::main]
async fn main() -> anyhow::Result<()> { async fn main() -> anyhow::Result<()> {
+1 -1
View File
@@ -29,7 +29,7 @@ impl GenericPrinter for KlipperPrinter {
Ok(()) Ok(())
} }
async fn publish(&mut self, payload: String) -> Result<(), PrinterError> { async fn publish(&mut self, _payload: String) -> Result<(), PrinterError> {
// TODO: add publishing via HTTP // TODO: add publishing via HTTP
Ok(()) Ok(())
} }
+17 -7
View File
@@ -38,7 +38,7 @@ mod prusa;
pub use bambu::{BambuPrinter, BambuProtocolPreference, BambuProtocolVersion, BambuTls}; pub use bambu::{BambuPrinter, BambuProtocolPreference, BambuProtocolVersion, BambuTls};
pub use bambu_commands::{ pub use bambu_commands::{
AmsState, AmsTray, AmsUnit, BambuReport, BambuRequest, CommandEnvelope, EmptyTray, GetVersionRequest, AmsState, AmsTray, AmsUnit, BambuReport, BambuRequest, CommandEnvelope, EmptyTray, GetVersionRequest,
GetVersionResponse, LoadedTray, PrintReport, PushallRequest, XcamSettings, GetVersionResponse, LoadedTray, ModuleInfo, PrintReport, PushallRequest, XcamSettings,
}; };
pub use klipper::KlipperPrinter; pub use klipper::KlipperPrinter;
pub use prusa::{PrusaLinkPrinter, PrusaSerialPrinter}; pub use prusa::{PrusaLinkPrinter, PrusaSerialPrinter};
@@ -59,6 +59,19 @@ pub struct PrinterBase {
/// The shared interface - think `interface GenericPrinter` (Java/TS) or an /// The shared interface - think `interface GenericPrinter` (Java/TS) or an
/// ABC (Python). Every vendor's struct implements this. /// ABC (Python). Every vendor's struct implements this.
///
/// The `allow` is a considered decision, not a brush-off. `async fn` in a
/// public trait means callers cannot require the returned futures to be
/// `Send`, so such a future cannot be moved to another OS thread. That is
/// fine here, and checked: the daemon does run on tokio's multi-threaded
/// runtime, but every printer is reached through one `Arc<Mutex<Vec<..>>>`
/// from the uplink's own task (see `uplink::SharedFleet`), so these futures
/// are created and polled in the same place. Revisit if a printer ever gets
/// its own task - the fix is to desugar to
/// `fn connect(&mut self) -> impl Future<Output = ..> + Send`, which cannot
/// be done without changing every implementation, which is why it is not
/// done pre-emptively.
#[allow(async_fn_in_trait)]
pub trait GenericPrinter { pub trait GenericPrinter {
/// Read-only access to the shared fields. /// Read-only access to the shared fields.
fn base(&self) -> &PrinterBase; fn base(&self) -> &PrinterBase;
@@ -67,14 +80,11 @@ pub trait GenericPrinter {
/// so there's nothing sensible to share here. Each `impl` in /// so there's nothing sensible to share here. Each `impl` in
/// `bambu.rs`/`prusa.rs`/`klipper.rs` provides a totally different /// `bambu.rs`/`prusa.rs`/`klipper.rs` provides a totally different
/// body - that's the override. /// body - that's the override.
///
/// `cargo check` will warn about `async fn` in a public trait here.
/// That's about a more advanced concern (whether the resulting work can
/// safely move across OS threads) that only matters once this is wired
/// into the multi-threaded daemon - safe to ignore for now.
async fn connect(&mut self) -> Result<(), PrinterError>; async fn connect(&mut self) -> Result<(), PrinterError>;
/// Sends one already-encoded message by whatever transport this vendor
/// uses. Lower level than the methods below and mostly a building block
/// for them - `bambu.rs` publishes MQTT with it; the stubs only log.
async fn publish(&mut self, payload: String) -> Result<(), PrinterError>; async fn publish(&mut self, payload: String) -> Result<(), PrinterError>;
/// REQUIRED, no default body: `percent` is 0-100, but how it actually /// REQUIRED, no default body: `percent` is 0-100, but how it actually
+2 -2
View File
@@ -29,7 +29,7 @@ impl GenericPrinter for PrusaLinkPrinter {
Ok(()) Ok(())
} }
async fn publish(&mut self, payload: String) -> Result<(), PrinterError> { async fn publish(&mut self, _payload: String) -> Result<(), PrinterError> {
// TODO: add publishing via HTTP // TODO: add publishing via HTTP
Ok(()) Ok(())
} }
@@ -100,7 +100,7 @@ impl GenericPrinter for PrusaSerialPrinter {
Ok(()) Ok(())
} }
async fn publish(&mut self, payload: String) -> Result<(), PrinterError> { async fn publish(&mut self, _payload: String) -> Result<(), PrinterError> {
// TODO: add publishing via serial // TODO: add publishing via serial
Ok(()) Ok(())
} }