text_mirror/lib.rs
1//! Converts binary and rich files into plain text and builds a replica
2//! text-mirror tree beside a provenance manifest.
3//!
4//! The manifest schema `text-mirror/manifest@1` is the public
5//! interface. The [`manifest`] module holds its serde types. See
6//! `docs/DESIGN.md` for the architecture.
7//!
8//! In-process converters cover text, Office and OpenDocument
9//! documents, and spreadsheets. Text-layer PDF and the media adapters
10//! run behind the sandbox [`runner`] in a jailed worker. A format no
11//! converter claims, or one whose adapter engine is not pinned yet, is
12//! inventoried by [`detect`] and recorded as `unsupported`, so the
13//! manifest always reports the true denominator.
14
15#![forbid(unsafe_code)]
16
17use std::path::{Path, PathBuf};
18
19use thiserror::Error as ThisError;
20
21pub mod bundle;
22pub mod convert;
23pub mod detect;
24pub mod hash;
25pub mod manifest;
26pub mod mirror;
27pub mod pipeline;
28pub mod report;
29#[cfg(unix)]
30pub mod runner;
31pub mod segments;
32pub mod walk;
33
34/// The typed adapter request and response bodies, re-exported so
35/// transcript rendering and tests reach them on every platform. On a
36/// unix target these are the same types the [`runner`] protocol uses.
37#[cfg(unix)]
38pub use runner::protocol::bodies as runner_bodies;
39
40/// Standalone copies of the transcript-shaped bodies for platforms
41/// without a jail backend, so transcript rendering still type-checks.
42#[cfg(not(unix))]
43pub mod runner_bodies {
44 use serde::{Deserialize, Serialize};
45
46 /// One transcribed speech segment.
47 #[derive(Debug, Clone, Serialize, Deserialize)]
48 pub struct AsrSegment {
49 /// Segment start in seconds.
50 pub start_seconds: f64,
51 /// Segment end in seconds.
52 pub end_seconds: f64,
53 /// One-based speaker index.
54 pub speaker: u32,
55 /// The transcribed text.
56 pub text: String,
57 }
58
59 /// One deduplicated on-screen text state.
60 #[derive(Debug, Clone, Serialize, Deserialize)]
61 pub struct ScreenState {
62 /// When this state first appeared, in seconds.
63 pub first_seen_seconds: f64,
64 /// The on-screen text.
65 pub text: String,
66 }
67}
68
69/// Errors returned by this library.
70///
71/// Conversion failures are not errors. They are recorded outcomes in
72/// the manifest. This type covers the cases where the pipeline itself
73/// cannot proceed.
74#[derive(Debug, ThisError)]
75pub enum Error {
76 /// A filesystem operation failed.
77 #[error("{op} {path}: {source}")]
78 Io {
79 /// The operation that failed, such as `open` or `read`.
80 op: &'static str,
81 /// The path the operation touched.
82 path: PathBuf,
83 /// The underlying error.
84 #[source]
85 source: std::io::Error,
86 },
87
88 /// A rules file failed to parse or validate.
89 #[error("rules file {name}: {message}")]
90 Rules {
91 /// The rules file name.
92 name: String,
93 /// What went wrong.
94 message: String,
95 },
96
97 /// A manifest shard failed to parse or validate.
98 #[error("manifest {path} line {line}: {message}")]
99 Manifest {
100 /// The shard path.
101 path: PathBuf,
102 /// The one-based line number.
103 line: usize,
104 /// What went wrong.
105 message: String,
106 },
107
108 /// A manifest record could not be encoded.
109 #[error("encode manifest record for {path}: {message}")]
110 Encode {
111 /// The shard path.
112 path: PathBuf,
113 /// What went wrong.
114 message: String,
115 },
116
117 /// A division name is not usable as a shard file name.
118 #[error("invalid division name {name:?}: use ASCII letters, digits, hyphen, underscore")]
119 Division {
120 /// The rejected name.
121 name: String,
122 },
123
124 /// The run layout is invalid.
125 #[error("invalid layout: {message}")]
126 Layout {
127 /// What is wrong with the layout.
128 message: String,
129 },
130
131 /// A bundle verb examined its input and refused it, naming every
132 /// offender. Refusal is an outcome, distinct from a verb that
133 /// could not run.
134 #[error("{verb} refused: {}", problems.join("; "))]
135 Refused {
136 /// The verb that refused.
137 verb: &'static str,
138 /// Every offending file, record, or field.
139 problems: Vec<String>,
140 },
141}
142
143impl Error {
144 pub(crate) fn io(op: &'static str, path: &Path, source: std::io::Error) -> Self {
145 Error::Io {
146 op,
147 path: path.to_path_buf(),
148 source,
149 }
150 }
151}
152
153/// The result type used across this library.
154pub type Result<T> = std::result::Result<T, Error>;