ipp_printer_app/device.rs
1//! [`DeviceBackend`] trait: enumerate physical devices, resolve driver names,
2//! poll live status.
3
4use crate::flags::PrinterReason;
5use crate::printer::PrinterConfig;
6
7/// The media currently loaded in a device, as reported by a live poll. Drives
8/// the dynamic `media-ready` / `media-col-ready` IPP attributes.
9#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct ReadyMedia {
11 /// PWG self-describing media name (e.g. `om_40x30mm_40x30mm`).
12 pub name: String,
13 /// Width/height in hundredths of a millimetre (PWG units).
14 pub size_hmm: [i32; 2],
15 /// PWG media-type keyword (e.g. `labels`).
16 pub media_type: String,
17}
18
19/// Live status reported by [`DeviceBackend::poll_status`]. Returning `None`
20/// from the poll means "no update"; returning `Some(PollStatus)` replaces the
21/// reasons and, when the optional fields are set, the dynamic media/supply
22/// attributes.
23#[derive(Debug, Clone)]
24pub struct PollStatus {
25 /// Fresh `printer-state-reasons`.
26 pub reasons: PrinterReason,
27 /// Currently-loaded media, if the device can report it.
28 pub ready_media: Option<ReadyMedia>,
29 /// Remaining-supply level 0–100 (e.g. labels left on the roll), if known.
30 pub supply_percent: Option<u8>,
31}
32
33impl Default for PollStatus {
34 fn default() -> Self {
35 Self {
36 reasons: PrinterReason::empty(),
37 ready_media: None,
38 supply_percent: None,
39 }
40 }
41}
42
43impl PollStatus {
44 /// Convenience constructor for backends that only report reasons.
45 pub fn from_reasons(reasons: PrinterReason) -> Self {
46 Self {
47 reasons,
48 ..Default::default()
49 }
50 }
51}
52
53/// Enumerate physical printers and report their live health.
54///
55/// Implementations describe how to discover devices (e.g. via sysfs, BlueZ,
56/// USB enumeration) and how to map their identifying strings to a driver
57/// name registered with the framework.
58pub trait DeviceBackend: Send + Sync {
59 /// Call `emit(info, uri, device_id)` for each discovered device. The
60 /// closure returns `true` to continue enumeration, `false` to stop early.
61 fn list(&self, emit: &mut dyn FnMut(&str, &str, &str) -> bool);
62
63 /// Map a device's IEEE 1284 `device-id` string and URI to a driver name
64 /// that this backend recognises. Return `None` for "this isn't one of
65 /// mine, skip it".
66 fn driver_for_device(&self, device_id: &str, device_uri: &str) -> Option<String>;
67
68 /// Query live status for a registered printer. The background status loop
69 /// calls this on each idle printer and updates the IPP attributes when the
70 /// value changes. Returning `None` means "no update" (keep whatever the
71 /// registry already holds); returning `Some` carries the fresh reasons and,
72 /// optionally, the loaded media and remaining-supply level.
73 fn poll_status(&self, _config: &PrinterConfig) -> Option<PollStatus> {
74 None
75 }
76
77 /// Handle an `Identify-Printer` request (PWG 5100.14 §5.1) — make the
78 /// physical device announce itself (beep, flash an LED, …). `actions`
79 /// holds the requested `identify-actions` keywords (`display`, `sound`,
80 /// `flash`, `speak`); an empty slice means "use the default action".
81 /// Default: no-op.
82 fn identify(&self, _config: &PrinterConfig, _actions: &[String]) {}
83}