Skip to main content

printobserver_types/
lib.rs

1//! `printobserver-types`.
2//!
3//! Owns: the vocabulary every domain and every client must agree on, and only
4//! that — the identity rule ([`ids`]: the exported [`identifier!`] macro, its
5//! error, the UUID-v7 rule, and the three identifiers the envelope reaches),
6//! the representation rules ([`Timestamp`], [`RawBytes`], [`FileName`],
7//! [`Reported`] and [`Range`]), the event log's envelope ([`event`], with the
8//! image handle [`ImageRef`] it carries), the state a printer reports
9//! ([`PrinterState`], which two ports speak and neither may take from the
10//! other), and the schema toolkit ([`contract`]). It holds data and total functions over that data, never
11//! I/O.
12//!
13//! A type belongs here only if adding or changing one domain's concept does
14//! not require editing it. The event log is the case in point: [`event`]
15//! declares the envelope — an open [`EventKind`] name and an opaque payload —
16//! and **no kind**. Each kind is declared by the domain that owns the event, as
17//! a payload type implementing [`EventPayload`] under a `KIND` of its own, so
18//! that a domain adding an event edits its own crate and nothing central. The
19//! same holds for a domain's own shapes: a provider's wire format lives in its
20//! adapter, a port's vocabulary in the port, and the supervision domain's
21//! records — the print, the action, the intervention, the policy, the image —
22//! and the identifiers it mints live in the supervision domain, each declared
23//! into the schema set through [`TypeContract::of`] rather than through a
24//! list here.
25//!
26//! May depend on: no crate of this workspace. It is the root of the graph, so a
27//! type it does not hold is a type the rest of the workspace cannot agree on.
28//!
29//! # One authoritative source per restated fact
30//!
31//! The types here are declared once and imported by every consumer rather than
32//! re-declared. The JSON Schemas the clients and the agent's structured answer
33//! are validated against are **generated from these types** by the
34//! `printobserver-types:schemas` graph target, which the gate runs: a schema
35//! checked into `schemas/` that no longer matches what these types generate
36//! fails that target. Nothing transcribes a schema by hand, and nothing
37//! restates a field.
38//!
39//! [`contract`] is where that generation reads the declared set from: it is
40//! this crate's own claim about which types it declares and what a canonical
41//! value of each looks like.
42//!
43//! # The representations, stated once
44//!
45//! * **Identifiers.** Every identifier this system mints is a UUID version 7,
46//!   minted by the store, held as a distinct newtype per record, and serialized
47//!   as its lowercase hyphenated string. See [`ids`]; a domain declares its own
48//!   through the [`identifier!`] macro.
49//! * **Numbers.** Every temperature, factor, multiplier, percentage and
50//!   fraction is a 64-bit float. Every byte count and every integer identifier
51//!   an external system supplies is a 64-bit signed integer. Every duration is
52//!   whole seconds as a 64-bit signed integer.
53//! * **Timestamps.** Every timestamp is an instant in UTC, serialized as an RFC
54//!   3339 string with a zero offset. See [`Timestamp`].
55//! * **Optionality.** An optional field absent means *the source did not report
56//!   it*, and is never rendered as a zero, an empty string, or a default.
57//!   Absent serializes as absent and parses back as absent.
58//! * **Reported numbers.** A numeric field a domain declares a plausibility
59//!   range for is typed [`Reported<f64>`]. See [`reported`] for the whole rule,
60//!   including why a non-finite value is out of range and why one is refused
61//!   on emission; the ranges themselves are the declaring domain's.
62//!
63//! # Why `serde`, `schemars` and `serde_json` are re-exported
64//!
65//! The three port crates depend on this crate and on nothing else, and each of
66//! them declares request and answer shapes that cross a process boundary and so
67//! must derive the same traits these types derive. They reach the derive macros
68//! through [`serde`], [`schemars`] and [`serde_json`] here rather than by
69//! declaring a dependency of their own.
70
71pub mod contract;
72pub mod event;
73pub mod file_name;
74pub mod ids;
75pub mod image;
76pub mod printer_state;
77pub mod raw;
78pub mod reported;
79pub mod timestamp;
80
81pub use contract::{
82    EVENT_KIND_MARKER, Sample, TypeContract, WireField, declared, event_schema_of, schema_of,
83    wire_fields,
84};
85pub use event::{
86    EventBody, EventKind, EventKindError, EventPayload, EventRecord, EventSource, KIND_PATTERN,
87};
88pub use file_name::{FileName, FileNameError, FileNameRefusal, SEPARATORS};
89pub use ids::{EventId, IdentifierError, ImageId, PrintId};
90pub use image::ImageRef;
91pub use printer_state::PrinterState;
92pub use raw::RawBytes;
93pub use reported::{Range, Reported};
94pub use timestamp::{Timestamp, TimestampError};
95
96pub use schemars;
97pub use serde;
98pub use serde_json;