Skip to main content

ipp_printer_app/
printer.rs

1//! Per-printer configuration and runtime state.
2
3use std::sync::Arc;
4
5use parking_lot::RwLock;
6
7use crate::flags::PrinterReason;
8
9/// Static printer capabilities supplied by the consumer crate (typically
10/// loaded from a config file). Carries everything the framework needs to
11/// build the IPP `Get-Printer-Attributes` response.
12#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
13#[allow(missing_docs)]
14pub struct PrinterConfig {
15    pub name: String,
16    pub driver_name: String,
17    pub make_and_model: String,
18    pub device_id: String,
19    pub device_uri: String,
20    pub dpi: i32,
21    pub printhead_width_dots: u32,
22    pub media_names: Vec<String>,
23    pub media_sizes: Vec<[i32; 2]>,
24    /// Darkness 0–100 (maps to print density).
25    pub darkness: i32,
26}
27
28impl PrinterConfig {
29    /// Build the canonical `ipp://<host>:<port>/ipp/print/<name>` URI. If
30    /// `host` is unspecified (`0.0.0.0`, `::`, empty), advertises
31    /// `localhost` so CUPS and mDNS clients get a reachable address.
32    pub fn printer_uri(&self, host: &str, port: u16) -> String {
33        let h = if host == "0.0.0.0" || host == "::" || host.is_empty() {
34            "localhost"
35        } else {
36            host
37        };
38        format!("ipp://{h}:{port}/ipp/print/{}", self.name)
39    }
40}
41
42/// IPP `printer-state` enum (RFC 8011 §5.4.11).
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
44#[repr(u32)]
45#[allow(missing_docs)]
46pub enum IppPrinterState {
47    Idle = 3,
48    Processing = 4,
49    Stopped = 5,
50}
51
52/// Runtime printer entry in the server registry.
53#[derive(Debug, Clone)]
54#[allow(missing_docs)]
55pub struct PrinterRecord {
56    pub config: PrinterConfig,
57    pub state: IppPrinterState,
58    pub reasons: PrinterReason,
59    pub uuid: String,
60}
61
62impl PrinterRecord {
63    /// Wrap a config in a fresh record (state = `Idle`, no reasons set, new UUID).
64    pub fn new(config: PrinterConfig) -> Self {
65        Self {
66            uuid: uuid::Uuid::new_v4().to_string(),
67            state: IppPrinterState::Idle,
68            reasons: PrinterReason::empty(),
69            config,
70        }
71    }
72}
73
74/// Borrowed view of a printer passed into [`crate::RasterDriver`] callbacks.
75///
76/// `record` is exposed for direct access; the helpers below are the
77/// commonly-needed shortcuts.
78pub struct PrinterHandle<'a> {
79    /// The underlying registry entry.
80    pub record: &'a PrinterRecord,
81}
82
83impl<'a> PrinterHandle<'a> {
84    /// Driver name from the config (matches the value supplied by
85    /// [`crate::DeviceBackend::driver_for_device`]).
86    pub fn driver_name(&self) -> &str {
87        &self.record.config.driver_name
88    }
89
90    /// Configured darkness, 0–100.
91    pub fn darkness(&self) -> i32 {
92        self.record.config.darkness
93    }
94
95    /// Printhead width in dots.
96    pub fn printhead_width_dots(&self) -> u32 {
97        self.record.config.printhead_width_dots
98    }
99}
100
101/// Shared printer registry. Cheap to clone (it's an `Arc`).
102pub type PrinterRegistry = Arc<RwLock<Vec<PrinterRecord>>>;