1use std::path::{Path, PathBuf};
5
6use serde::{Deserialize, Serialize};
7
8use crate::limits::Limits;
9
10#[derive(Clone, Copy, Debug)]
12pub enum Source<'a> {
13 Path(&'a Path),
14 Bytes(&'a [u8]),
15}
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
18#[serde(rename_all = "lowercase")]
19pub enum Format {
20 Pdf,
21 Docx,
22 Xlsx,
23}
24
25impl Format {
26 pub fn as_str(self) -> &'static str {
27 match self {
28 Format::Pdf => "pdf",
29 Format::Docx => "docx",
30 Format::Xlsx => "xlsx",
31 }
32 }
33}
34
35#[derive(Clone, Debug, Serialize, Deserialize)]
37#[serde(rename_all = "camelCase", default)]
38pub struct ReadOptions {
39 pub limits: Limits,
40 pub pages: Option<Vec<u32>>,
42 pub sheets: Option<Vec<String>>,
44 pub range: Option<String>,
46 pub max_chars: usize,
48 pub max_cells: usize,
50 pub markdown: bool,
52}
53
54impl Default for ReadOptions {
55 fn default() -> Self {
56 Self {
57 limits: Limits::default(),
58 pages: None,
59 sheets: None,
60 range: None,
61 max_chars: 200_000,
62 max_cells: 50_000,
63 markdown: true,
64 }
65 }
66}
67
68#[derive(Clone, Debug, Serialize, Deserialize)]
69#[serde(rename_all = "camelCase")]
70pub struct DocumentRead {
71 pub format: Format,
72 pub sha256: String,
75 pub size_bytes: u64,
76 pub text: String,
78 pub markdown: Option<String>,
79 pub truncated: bool,
81 pub content: Content,
82 pub omitted: Vec<String>,
86}
87
88#[derive(Clone, Debug, Serialize, Deserialize)]
89#[serde(tag = "kind", rename_all = "camelCase")]
90pub enum Content {
91 Docx(DocxContent),
92 Xlsx(XlsxContent),
93 Pdf(PdfContent),
94}
95
96#[derive(Clone, Debug, Serialize, Deserialize)]
97#[serde(rename_all = "camelCase")]
98pub struct DocxContent {
99 pub blocks: Vec<DocxBlock>,
100 pub headers: Vec<String>,
101 pub footers: Vec<String>,
102}
103
104#[derive(Clone, Debug, Serialize, Deserialize)]
105#[serde(tag = "kind", rename_all = "camelCase")]
106pub enum DocxBlock {
107 Paragraph {
109 style: Option<String>,
110 list: bool,
111 text: String,
112 },
113 Table {
114 rows: Vec<Vec<String>>,
115 },
116}
117
118#[derive(Clone, Debug, Serialize, Deserialize)]
119#[serde(rename_all = "camelCase")]
120pub struct XlsxContent {
121 pub sheets: Vec<SheetRead>,
122}
123
124#[derive(Clone, Debug, Serialize, Deserialize)]
125#[serde(rename_all = "camelCase")]
126pub struct SheetRead {
127 pub name: String,
128 pub state: String,
130 pub used_range: Option<String>,
132 pub cells: Vec<CellRead>,
136 pub truncated: bool,
137}
138
139#[derive(Clone, Debug, Serialize, Deserialize)]
140#[serde(rename_all = "camelCase")]
141pub struct CellRead {
142 pub cell: String,
144 pub row: u32,
146 pub col: u32,
148 pub value: CellValue,
149 pub formula: Option<String>,
151}
152
153#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
154#[serde(tag = "type", content = "value", rename_all = "camelCase")]
155pub enum CellValue {
156 Empty,
157 Text(String),
158 Number(f64),
159 Bool(bool),
160 DateTime {
162 serial: f64,
163 iso: Option<String>,
164 },
165 Duration(f64),
167 Error(String),
169}
170
171#[derive(Clone, Debug, Serialize, Deserialize)]
172#[serde(rename_all = "camelCase")]
173pub struct PdfContent {
174 pub page_count: u32,
175 pub pages: Vec<PdfPageText>,
176}
177
178#[derive(Clone, Debug, Serialize, Deserialize)]
179#[serde(rename_all = "camelCase")]
180pub struct PdfPageText {
181 pub page: u32,
183 pub text: String,
184}
185
186#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
192#[serde(tag = "kind", rename_all = "camelCase")]
193pub enum Block {
194 Heading {
196 level: u8,
197 text: String,
198 },
199 Paragraph {
200 text: String,
201 },
202 Bullet {
203 text: String,
204 },
205 Numbered {
206 text: String,
207 },
208 Table {
209 rows: Vec<Vec<String>>,
210 header: bool,
211 },
212 PageBreak,
213}
214
215#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
218#[serde(tag = "type", content = "value", rename_all = "camelCase")]
219pub enum CellInput {
220 Text(String),
221 Number(f64),
222 Bool(bool),
223 Formula(String),
225 Blank,
226}
227
228#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
229#[serde(rename_all = "camelCase")]
230pub struct SheetSpec {
231 pub name: String,
232 pub rows: Vec<Vec<CellInput>>,
234}
235
236#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
237#[serde(rename_all = "camelCase")]
238pub struct CellSet {
239 pub cell: String,
241 pub value: CellInput,
242}
243
244#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
247#[serde(tag = "kind", rename_all = "camelCase")]
248pub enum Op {
249 CreateDocx { blocks: Vec<Block> },
251 CreateXlsx { sheets: Vec<SheetSpec> },
253 ReplaceText { find: String, replace: String },
255 AppendBlocks { blocks: Vec<Block> },
257 SetCells { sheet: String, cells: Vec<CellSet> },
259 AppendRows {
261 sheet: String,
262 rows: Vec<Vec<CellInput>>,
263 },
264 AddPdfText {
266 page: u32,
267 x: f64,
268 y: f64,
269 text: String,
270 size_pt: Option<f64>,
271 },
272 SelectPdfPages { pages: Vec<u32> },
274}
275
276#[derive(Clone, Debug, Default, Serialize, Deserialize)]
277#[serde(rename_all = "camelCase", default)]
278pub struct WriteOptions {
279 pub limits: Limits,
280 pub expect_sha256: Option<String>,
285 pub overwrite: bool,
287}
288
289#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
292#[serde(rename_all = "camelCase")]
293pub struct Loss {
294 pub part: String,
295 pub kind: String,
296 pub detail: String,
297}
298
299#[derive(Clone, Debug, Serialize, Deserialize)]
300#[serde(rename_all = "camelCase")]
301pub struct WriteReceipt {
302 pub path: PathBuf,
303 pub format: Format,
304 pub created: bool,
306 pub source_sha256: Option<String>,
308 pub sha256: String,
309 pub bytes_written: u64,
310 pub ops_applied: usize,
311 pub replacements: usize,
314 pub cells_set: usize,
315 pub rows_appended: usize,
316 pub touched_parts: Vec<String>,
318 pub losses: Vec<Loss>,
319 pub warnings: Vec<String>,
320}