1use std::collections::HashMap;
2
3use serde::{Deserialize, Serialize};
4
5fn default_text_run_type() -> TextRunNodeType {
6 TextRunNodeType::Text
7}
8
9fn default_image_run_type() -> ImageRunNodeType {
10 ImageRunNodeType::Image
11}
12
13fn default_form_field_run_type() -> FormFieldRunNodeType {
14 FormFieldRunNodeType::FormField
15}
16
17fn default_paragraph_node_type() -> ParagraphNodeType {
18 ParagraphNodeType::Paragraph
19}
20
21fn default_table_cell_node_type() -> TableCellNodeType {
22 TableCellNodeType::TableCell
23}
24
25fn default_table_row_node_type() -> TableRowNodeType {
26 TableRowNodeType::TableRow
27}
28
29fn default_table_node_type() -> TableNodeType {
30 TableNodeType::Table
31}
32
33#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
35#[serde(rename_all = "camelCase")]
36pub enum ParagraphAlignment {
37 Left,
38 Center,
39 Right,
40 Justify,
41}
42
43#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
45#[serde(into = "i64")]
46pub enum HeadingLevel {
47 One = 1,
48 Two = 2,
49 Three = 3,
50 Four = 4,
51 Five = 5,
52 Six = 6,
53 Seven = 7,
54 Eight = 8,
55 Nine = 9,
56}
57
58impl<'de> Deserialize<'de> for HeadingLevel {
59 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
60 where
61 D: serde::Deserializer<'de>,
62 {
63 let value = i64::deserialize(deserializer)?;
64 match value {
65 1 => Ok(HeadingLevel::One),
66 2 => Ok(HeadingLevel::Two),
67 3 => Ok(HeadingLevel::Three),
68 4 => Ok(HeadingLevel::Four),
69 5 => Ok(HeadingLevel::Five),
70 6 => Ok(HeadingLevel::Six),
71 7 => Ok(HeadingLevel::Seven),
72 8 => Ok(HeadingLevel::Eight),
73 9 => Ok(HeadingLevel::Nine),
74 _ => Err(serde::de::Error::custom(format!(
75 "invalid heading level {value}"
76 ))),
77 }
78 }
79}
80
81impl From<HeadingLevel> for i64 {
82 fn from(value: HeadingLevel) -> Self {
83 value as i64
84 }
85}
86
87#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
89#[serde(rename_all = "camelCase")]
90pub struct TextRunBorderStyle {
91 #[serde(rename = "type")]
92 pub border_type: String,
93 #[serde(skip_serializing_if = "Option::is_none")]
94 pub color: Option<String>,
95 #[serde(skip_serializing_if = "Option::is_none")]
96 pub size_eighth_pt: Option<f64>,
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub space_pt: Option<f64>,
99 #[serde(skip_serializing_if = "Option::is_none")]
100 pub frame: Option<bool>,
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub shadow: Option<bool>,
103}
104
105#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
107#[serde(rename_all = "camelCase")]
108pub enum VerticalAlign {
109 #[serde(rename = "superscript")]
110 Superscript,
111 #[serde(rename = "subscript")]
112 Subscript,
113}
114
115#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
116#[serde(rename_all = "camelCase")]
117pub enum TextLigatures {
118 None,
119 Standard,
120 Contextual,
121 Historical,
122 Discretional,
123 StandardContextual,
124 StandardHistorical,
125 ContextualHistorical,
126 StandardDiscretional,
127 ContextualDiscretional,
128 HistoricalDiscretional,
129 StandardContextualHistorical,
130 StandardContextualDiscretional,
131 StandardHistoricalDiscretional,
132 ContextualHistoricalDiscretional,
133 All,
134}
135
136impl TextLigatures {
137 pub fn from_xml_value(value: &str) -> Option<Self> {
138 match value {
139 "none" => Some(Self::None),
140 "standard" => Some(Self::Standard),
141 "contextual" => Some(Self::Contextual),
142 "historical" => Some(Self::Historical),
143 "discretional" => Some(Self::Discretional),
144 "standardContextual" => Some(Self::StandardContextual),
145 "standardHistorical" => Some(Self::StandardHistorical),
146 "contextualHistorical" => Some(Self::ContextualHistorical),
147 "standardDiscretional" => Some(Self::StandardDiscretional),
148 "contextualDiscretional" => Some(Self::ContextualDiscretional),
149 "historicalDiscretional" => Some(Self::HistoricalDiscretional),
150 "standardContextualHistorical" => Some(Self::StandardContextualHistorical),
151 "standardContextualDiscretional" => Some(Self::StandardContextualDiscretional),
152 "standardHistoricalDiscretional" => Some(Self::StandardHistoricalDiscretional),
153 "contextualHistoricalDiscretional" => Some(Self::ContextualHistoricalDiscretional),
154 "all" => Some(Self::All),
155 _ => None,
156 }
157 }
158
159 pub fn xml_value(self) -> &'static str {
160 match self {
161 Self::None => "none",
162 Self::Standard => "standard",
163 Self::Contextual => "contextual",
164 Self::Historical => "historical",
165 Self::Discretional => "discretional",
166 Self::StandardContextual => "standardContextual",
167 Self::StandardHistorical => "standardHistorical",
168 Self::ContextualHistorical => "contextualHistorical",
169 Self::StandardDiscretional => "standardDiscretional",
170 Self::ContextualDiscretional => "contextualDiscretional",
171 Self::HistoricalDiscretional => "historicalDiscretional",
172 Self::StandardContextualHistorical => "standardContextualHistorical",
173 Self::StandardContextualDiscretional => "standardContextualDiscretional",
174 Self::StandardHistoricalDiscretional => "standardHistoricalDiscretional",
175 Self::ContextualHistoricalDiscretional => "contextualHistoricalDiscretional",
176 Self::All => "all",
177 }
178 }
179}
180
181#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
183#[serde(rename_all = "camelCase")]
184pub struct TextStyle {
185 #[serde(skip_serializing_if = "Option::is_none")]
186 pub bold: Option<bool>,
187 #[serde(skip_serializing_if = "Option::is_none")]
188 pub italic: Option<bool>,
189 #[serde(skip_serializing_if = "Option::is_none")]
190 pub underline: Option<bool>,
191 #[serde(skip_serializing_if = "Option::is_none")]
192 pub strike: Option<bool>,
193 #[serde(skip_serializing_if = "Option::is_none")]
194 pub all_caps: Option<bool>,
195 #[serde(skip_serializing_if = "Option::is_none")]
196 pub small_caps: Option<bool>,
197 #[serde(skip_serializing_if = "Option::is_none")]
198 pub color: Option<String>,
199 #[serde(skip_serializing_if = "Option::is_none")]
200 pub highlight: Option<String>,
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub background_color: Option<String>,
203 #[serde(skip_serializing_if = "Option::is_none")]
204 pub font_size_pt: Option<f64>,
205 #[serde(skip_serializing_if = "Option::is_none")]
206 pub font_size_cs_pt: Option<f64>,
207 #[serde(skip_serializing_if = "Option::is_none")]
208 pub font_family: Option<String>,
209 #[serde(skip_serializing_if = "Option::is_none")]
212 pub source_font_family: Option<String>,
213 #[serde(skip_serializing_if = "Option::is_none")]
216 pub font_family_ascii: Option<String>,
217 #[serde(skip_serializing_if = "Option::is_none")]
218 pub font_family_h_ansi: Option<String>,
219 #[serde(skip_serializing_if = "Option::is_none")]
220 pub font_family_east_asia: Option<String>,
221 #[serde(skip_serializing_if = "Option::is_none")]
222 pub font_family_cs: Option<String>,
223 #[serde(skip_serializing_if = "Option::is_none")]
224 pub font_theme_ascii: Option<String>,
225 #[serde(skip_serializing_if = "Option::is_none")]
226 pub font_theme_h_ansi: Option<String>,
227 #[serde(skip_serializing_if = "Option::is_none")]
228 pub font_theme_east_asia: Option<String>,
229 #[serde(skip_serializing_if = "Option::is_none")]
230 pub font_theme_cs: Option<String>,
231 #[serde(skip_serializing_if = "Option::is_none")]
232 pub resolved_font_family_ascii: Option<String>,
233 #[serde(skip_serializing_if = "Option::is_none")]
234 pub resolved_font_family_h_ansi: Option<String>,
235 #[serde(skip_serializing_if = "Option::is_none")]
236 pub resolved_font_family_east_asia: Option<String>,
237 #[serde(skip_serializing_if = "Option::is_none")]
238 pub resolved_font_family_cs: Option<String>,
239 #[serde(skip_serializing_if = "Option::is_none")]
240 pub font_hint: Option<String>,
241 #[serde(skip_serializing_if = "Option::is_none")]
244 pub language: Option<String>,
245 #[serde(skip_serializing_if = "Option::is_none")]
246 pub language_east_asia: Option<String>,
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub language_bidi: Option<String>,
249 #[serde(skip_serializing_if = "Option::is_none")]
250 pub right_to_left: Option<bool>,
251 #[serde(skip_serializing_if = "Option::is_none")]
252 pub complex_script: Option<bool>,
253 #[serde(skip_serializing_if = "Option::is_none")]
254 pub character_spacing_twips: Option<i64>,
255 #[serde(skip_serializing_if = "Option::is_none")]
256 pub character_scale_percent: Option<u16>,
257 #[serde(skip_serializing_if = "Option::is_none")]
258 pub source_character_scale: Option<String>,
259 #[serde(skip_serializing_if = "Option::is_none")]
260 pub kerning_min_font_size_pt: Option<f64>,
261 #[serde(skip_serializing_if = "Option::is_none")]
262 pub ligatures: Option<TextLigatures>,
263 #[serde(skip_serializing_if = "Option::is_none")]
264 pub contextual_alternates: Option<bool>,
265 #[serde(skip_serializing_if = "Option::is_none")]
266 pub vertical_align: Option<VerticalAlign>,
267 #[serde(skip_serializing_if = "Option::is_none")]
268 pub run_border: Option<TextRunBorderStyle>,
269}
270
271#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
273#[serde(transparent)]
274pub struct SharedTextStyle(std::sync::Arc<TextStyle>);
275
276impl SharedTextStyle {
277 pub fn into_owned(self) -> TextStyle {
278 std::sync::Arc::unwrap_or_clone(self.0)
279 }
280}
281
282impl From<TextStyle> for SharedTextStyle {
283 fn from(style: TextStyle) -> Self {
284 Self(std::sync::Arc::new(style))
285 }
286}
287
288impl std::ops::Deref for SharedTextStyle {
289 type Target = TextStyle;
290
291 fn deref(&self) -> &TextStyle {
292 &self.0
293 }
294}
295
296impl std::ops::DerefMut for SharedTextStyle {
297 fn deref_mut(&mut self) -> &mut TextStyle {
298 std::sync::Arc::make_mut(&mut self.0)
299 }
300}
301
302#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
304#[serde(rename_all = "camelCase")]
305pub struct NoteReference {
306 pub kind: NoteReferenceKind,
307 pub id: i64,
308}
309
310#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
312pub enum NoteReferenceKind {
313 #[serde(rename = "footnote")]
314 Footnote,
315 #[serde(rename = "endnote")]
316 Endnote,
317}
318
319#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
321#[serde(rename_all = "camelCase")]
322pub struct TextRunNode {
323 #[serde(default = "default_text_run_type", rename = "type")]
324 pub r#type: TextRunNodeType,
325 pub text: String,
326 #[serde(skip_serializing_if = "Option::is_none")]
327 pub style: Option<SharedTextStyle>,
328 #[serde(skip_serializing_if = "Option::is_none")]
329 pub link: Option<String>,
330 #[serde(skip_serializing_if = "Option::is_none")]
331 pub note_reference: Option<NoteReference>,
332}
333
334#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
336pub enum TextRunNodeType {
337 #[serde(rename = "text")]
338 Text,
339}
340
341#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
343#[serde(rename_all = "camelCase")]
344pub struct ImageCrop {
345 #[serde(skip_serializing_if = "Option::is_none")]
346 pub left_fraction: Option<f64>,
347 #[serde(skip_serializing_if = "Option::is_none")]
348 pub top_fraction: Option<f64>,
349 #[serde(skip_serializing_if = "Option::is_none")]
350 pub right_fraction: Option<f64>,
351 #[serde(skip_serializing_if = "Option::is_none")]
352 pub bottom_fraction: Option<f64>,
353}
354
355#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
357#[serde(rename_all = "camelCase")]
358pub enum ImageHorizontalAlign {
359 Left,
360 Center,
361 Right,
362 Inside,
363 Outside,
364}
365
366#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
368#[serde(rename_all = "camelCase")]
369pub enum ImageVerticalAlign {
370 Top,
371 Center,
372 Bottom,
373 Inside,
374 Outside,
375}
376
377#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
379#[serde(rename_all = "camelCase")]
380pub enum ImageWrapType {
381 #[serde(rename = "none")]
382 WrapNone,
383 #[serde(rename = "square")]
384 Square,
385 #[serde(rename = "tight")]
386 Tight,
387 #[serde(rename = "through")]
388 Through,
389 #[serde(rename = "topAndBottom")]
390 TopAndBottom,
391}
392
393#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
395#[serde(rename_all = "camelCase")]
396pub enum ImageWrapText {
397 #[serde(rename = "bothSides")]
398 BothSides,
399 #[serde(rename = "left")]
400 Left,
401 #[serde(rename = "right")]
402 Right,
403 #[serde(rename = "largest")]
404 Largest,
405}
406
407#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
409#[serde(rename_all = "camelCase")]
410pub struct ImageFloating {
411 #[serde(skip_serializing_if = "Option::is_none")]
412 pub x_px: Option<f64>,
413 #[serde(skip_serializing_if = "Option::is_none")]
414 pub y_px: Option<f64>,
415 #[serde(skip_serializing_if = "Option::is_none")]
416 pub horizontal_align: Option<ImageHorizontalAlign>,
417 #[serde(skip_serializing_if = "Option::is_none")]
418 pub vertical_align: Option<ImageVerticalAlign>,
419 #[serde(skip_serializing_if = "Option::is_none")]
420 pub horizontal_relative_to: Option<String>,
421 #[serde(skip_serializing_if = "Option::is_none")]
422 pub vertical_relative_to: Option<String>,
423 #[serde(skip_serializing_if = "Option::is_none")]
424 pub dist_l_px: Option<f64>,
425 #[serde(skip_serializing_if = "Option::is_none")]
426 pub dist_r_px: Option<f64>,
427 #[serde(skip_serializing_if = "Option::is_none")]
428 pub dist_t_px: Option<f64>,
429 #[serde(skip_serializing_if = "Option::is_none")]
430 pub dist_b_px: Option<f64>,
431 #[serde(skip_serializing_if = "Option::is_none")]
432 pub wrap_type: Option<ImageWrapType>,
433 #[serde(skip_serializing_if = "Option::is_none")]
434 pub wrap_text: Option<ImageWrapText>,
435 #[serde(skip_serializing_if = "Option::is_none")]
436 pub behind_document: Option<bool>,
437 #[serde(skip_serializing_if = "Option::is_none")]
438 pub z_index: Option<i64>,
439}
440
441#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
442#[serde(rename_all = "camelCase")]
443pub struct ImagePaintBounds {
444 pub x_px: f64,
445 pub y_px: f64,
446 pub width_px: f64,
447 pub height_px: f64,
448 pub layout_width_px: f64,
449 pub layout_height_px: f64,
450}
451
452#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
454#[serde(rename_all = "camelCase")]
455pub struct ImageRunNode {
456 #[serde(default, skip_serializing_if = "Option::is_none")]
457 pub paint_bounds: Option<Box<ImagePaintBounds>>,
458 #[serde(default, skip_serializing_if = "Option::is_none")]
459 pub math_ml: Option<String>,
460 #[serde(default, skip_serializing_if = "Option::is_none")]
461 pub content_nodes: Option<Vec<DocNode>>,
462 #[serde(default, skip_serializing_if = "Option::is_none")]
463 pub semantic_kind: Option<String>,
464 #[serde(default, skip_serializing_if = "Option::is_none")]
465 pub block_id: Option<String>,
466 #[serde(default = "default_image_run_type", rename = "type")]
467 pub r#type: ImageRunNodeType,
468 #[serde(skip_serializing_if = "Option::is_none")]
469 pub src: Option<String>,
470 #[serde(skip_serializing_if = "Option::is_none")]
471 pub alt: Option<String>,
472 #[serde(skip_serializing_if = "Option::is_none")]
473 pub width_px: Option<f64>,
474 #[serde(skip_serializing_if = "Option::is_none")]
475 pub height_px: Option<f64>,
476 #[serde(skip_serializing_if = "Option::is_none")]
477 pub part_name: Option<String>,
478 #[serde(skip_serializing_if = "Option::is_none")]
479 pub content_type: Option<String>,
480 #[serde(default, skip_serializing_if = "Option::is_none")]
481 pub data: Option<Vec<u8>>,
482 #[serde(skip_serializing_if = "Option::is_none")]
483 pub source_xml: Option<String>,
484 #[serde(skip_serializing_if = "Option::is_none")]
485 pub crop: Option<ImageCrop>,
486 #[serde(skip_serializing_if = "Option::is_none")]
487 pub css_filter: Option<String>,
488 #[serde(skip_serializing_if = "Option::is_none")]
489 pub css_opacity: Option<f64>,
490 #[serde(skip_serializing_if = "Option::is_none")]
491 pub floating: Option<ImageFloating>,
492 #[serde(skip_serializing_if = "Option::is_none")]
493 pub synthetic_text_box: Option<bool>,
494 #[serde(skip_serializing_if = "Option::is_none")]
495 pub text_box_text: Option<String>,
496}
497
498#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
500pub enum ImageRunNodeType {
501 #[serde(rename = "image")]
502 Image,
503}
504
505#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
507#[serde(rename_all = "camelCase")]
508pub enum FormFieldType {
509 #[serde(rename = "checkbox")]
510 Checkbox,
511 #[serde(rename = "text")]
512 Text,
513 #[serde(rename = "date")]
514 Date,
515 #[serde(rename = "dropdown")]
516 Dropdown,
517}
518
519#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
521pub enum FormFieldSourceKind {
522 #[serde(rename = "sdt")]
523 Sdt,
524 #[serde(rename = "legacy")]
525 Legacy,
526}
527
528#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
530#[serde(rename_all = "camelCase")]
531pub struct FormFieldOption {
532 pub display_text: String,
533 #[serde(skip_serializing_if = "Option::is_none")]
534 pub value: Option<String>,
535}
536
537#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
539#[serde(rename_all = "camelCase")]
540pub struct FormFieldTextWidgetSettings {
541 #[serde(skip_serializing_if = "Option::is_none")]
542 pub input_type: Option<String>,
543 #[serde(skip_serializing_if = "Option::is_none")]
544 pub default_text: Option<String>,
545 #[serde(skip_serializing_if = "Option::is_none")]
546 pub max_length: Option<i64>,
547 #[serde(skip_serializing_if = "Option::is_none")]
548 pub text_format: Option<String>,
549}
550
551#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
553#[serde(rename_all = "camelCase")]
554pub struct FormFieldCheckboxWidgetSettings {
555 #[serde(skip_serializing_if = "Option::is_none")]
556 pub default_checked: Option<bool>,
557 #[serde(skip_serializing_if = "Option::is_none")]
558 pub size_mode: Option<FormFieldCheckboxSizeMode>,
559 #[serde(skip_serializing_if = "Option::is_none")]
560 pub size_pt: Option<f64>,
561}
562
563#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
565pub enum FormFieldCheckboxSizeMode {
566 #[serde(rename = "auto")]
567 Auto,
568 #[serde(rename = "exact")]
569 Exact,
570}
571
572#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
574#[serde(rename_all = "camelCase")]
575pub struct FormFieldDropdownWidgetSettings {
576 #[serde(skip_serializing_if = "Option::is_none")]
577 pub default_value: Option<String>,
578}
579
580#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
582#[serde(rename_all = "camelCase")]
583pub struct FormFieldWidgetSettings {
584 #[serde(skip_serializing_if = "Option::is_none")]
585 pub name: Option<String>,
586 #[serde(skip_serializing_if = "Option::is_none")]
587 pub enabled: Option<bool>,
588 #[serde(skip_serializing_if = "Option::is_none")]
589 pub calc_on_exit: Option<bool>,
590 #[serde(skip_serializing_if = "Option::is_none")]
591 pub text: Option<FormFieldTextWidgetSettings>,
592 #[serde(skip_serializing_if = "Option::is_none")]
593 pub checkbox: Option<FormFieldCheckboxWidgetSettings>,
594 #[serde(skip_serializing_if = "Option::is_none")]
595 pub dropdown: Option<FormFieldDropdownWidgetSettings>,
596}
597
598#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
599#[serde(rename_all = "camelCase")]
600pub struct FormFieldSourcePreview {
601 pub relationship_id: String,
602 pub shape_id: String,
603 pub checked: bool,
604 pub image: Box<ImageRunNode>,
605}
606
607#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
609#[serde(rename_all = "camelCase")]
610pub struct FormFieldRunNode {
611 #[serde(default = "default_form_field_run_type", rename = "type")]
612 pub r#type: FormFieldRunNodeType,
613 pub field_type: FormFieldType,
614 #[serde(skip_serializing_if = "Option::is_none")]
615 pub source_kind: Option<FormFieldSourceKind>,
616 #[serde(skip_serializing_if = "Option::is_none")]
617 pub id: Option<i64>,
618 #[serde(skip_serializing_if = "Option::is_none")]
619 pub tag: Option<String>,
620 #[serde(skip_serializing_if = "Option::is_none")]
621 pub title: Option<String>,
622 #[serde(skip_serializing_if = "Option::is_none")]
623 pub placeholder: Option<String>,
624 #[serde(skip_serializing_if = "Option::is_none")]
625 pub checked: Option<bool>,
626 #[serde(skip_serializing_if = "Option::is_none")]
627 pub value: Option<String>,
628 #[serde(skip_serializing_if = "Option::is_none")]
629 pub options: Option<Vec<FormFieldOption>>,
630 #[serde(skip_serializing_if = "Option::is_none")]
631 pub widget: Option<FormFieldWidgetSettings>,
632 #[serde(skip_serializing_if = "Option::is_none")]
633 pub checked_symbol: Option<String>,
634 #[serde(skip_serializing_if = "Option::is_none")]
635 pub unchecked_symbol: Option<String>,
636 #[serde(skip_serializing_if = "Option::is_none")]
637 pub style: Option<SharedTextStyle>,
638 #[serde(skip_serializing_if = "Option::is_none")]
639 pub link: Option<String>,
640 #[serde(skip_serializing_if = "Option::is_none")]
641 pub source_xml: Option<String>,
642 #[serde(default, skip_serializing_if = "Option::is_none")]
643 pub source_preview: Option<Box<FormFieldSourcePreview>>,
644}
645
646#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
648pub enum FormFieldRunNodeType {
649 #[serde(rename = "form-field")]
650 FormField,
651}
652
653#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
655#[serde(untagged)]
656pub enum ParagraphChildNode {
657 Text(TextRunNode),
658 Image(Box<ImageRunNode>),
659 FormField(Box<FormFieldRunNode>),
660}
661
662#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
664#[serde(rename_all = "camelCase")]
665pub struct ParagraphNumbering {
666 pub num_id: i64,
667 pub ilvl: i64,
668}
669
670#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
672pub enum ParagraphLineRule {
673 #[serde(rename = "auto")]
674 Auto,
675 #[serde(rename = "exact")]
676 Exact,
677 #[serde(rename = "atLeast")]
678 AtLeast,
679}
680
681#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
683#[serde(rename_all = "camelCase")]
684pub struct ParagraphSpacing {
685 #[serde(skip_serializing_if = "Option::is_none")]
686 pub before_twips: Option<i64>,
687 #[serde(skip_serializing_if = "Option::is_none")]
688 pub after_twips: Option<i64>,
689 #[serde(skip_serializing_if = "Option::is_none")]
690 pub before_auto_spacing: Option<bool>,
691 #[serde(skip_serializing_if = "Option::is_none")]
692 pub after_auto_spacing: Option<bool>,
693 #[serde(skip_serializing_if = "Option::is_none")]
694 pub line_twips: Option<i64>,
695 #[serde(skip_serializing_if = "Option::is_none")]
696 pub line_rule: Option<ParagraphLineRule>,
697}
698
699#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
701#[serde(rename_all = "camelCase")]
702pub struct ParagraphIndent {
703 #[serde(skip_serializing_if = "Option::is_none")]
704 pub left_twips: Option<i64>,
705 #[serde(skip_serializing_if = "Option::is_none")]
706 pub right_twips: Option<i64>,
707 #[serde(skip_serializing_if = "Option::is_none")]
708 pub first_line_twips: Option<i64>,
709 #[serde(skip_serializing_if = "Option::is_none")]
710 pub hanging_twips: Option<i64>,
711}
712
713#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
715#[serde(rename_all = "camelCase")]
716pub struct ParagraphBorderStyle {
717 #[serde(rename = "type")]
718 pub border_type: String,
719 #[serde(skip_serializing_if = "Option::is_none")]
720 pub color: Option<String>,
721 #[serde(skip_serializing_if = "Option::is_none")]
722 pub size_eighth_pt: Option<f64>,
723 #[serde(skip_serializing_if = "Option::is_none")]
724 pub space_pt: Option<f64>,
725 #[serde(skip_serializing_if = "Option::is_none")]
726 pub frame: Option<bool>,
727 #[serde(skip_serializing_if = "Option::is_none")]
728 pub shadow: Option<bool>,
729}
730
731#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
733#[serde(rename_all = "camelCase")]
734pub struct ParagraphBorderSet {
735 #[serde(skip_serializing_if = "Option::is_none")]
736 pub top: Option<ParagraphBorderStyle>,
737 #[serde(skip_serializing_if = "Option::is_none")]
738 pub right: Option<ParagraphBorderStyle>,
739 #[serde(skip_serializing_if = "Option::is_none")]
740 pub bottom: Option<ParagraphBorderStyle>,
741 #[serde(skip_serializing_if = "Option::is_none")]
742 pub left: Option<ParagraphBorderStyle>,
743 #[serde(skip_serializing_if = "Option::is_none")]
744 pub between: Option<ParagraphBorderStyle>,
745 #[serde(skip_serializing_if = "Option::is_none")]
746 pub bar: Option<ParagraphBorderStyle>,
747}
748
749#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
751#[serde(rename_all = "camelCase")]
752pub enum ParagraphTabStopAlignment {
753 Clear,
754 Left,
755 Center,
756 Right,
757 Decimal,
758 Bar,
759}
760
761#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
763pub enum ParagraphTabStopLeader {
764 #[serde(rename = "none")]
765 LeaderNone,
766 #[serde(rename = "dot")]
767 Dot,
768 #[serde(rename = "hyphen")]
769 Hyphen,
770 #[serde(rename = "underscore")]
771 Underscore,
772 #[serde(rename = "middleDot")]
773 MiddleDot,
774}
775
776#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
778#[serde(rename_all = "camelCase")]
779pub struct ParagraphTabStop {
780 #[serde(skip_serializing_if = "Option::is_none")]
781 pub alignment: Option<ParagraphTabStopAlignment>,
782 #[serde(skip_serializing_if = "Option::is_none")]
783 pub leader: Option<ParagraphTabStopLeader>,
784 #[serde(skip_serializing_if = "Option::is_none")]
785 pub position_twips: Option<i64>,
786}
787
788#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
790pub enum ParagraphDropCapType {
791 #[serde(rename = "drop")]
792 Drop,
793 #[serde(rename = "margin")]
794 Margin,
795}
796
797#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
799#[serde(rename_all = "camelCase")]
800pub struct ParagraphDropCap {
801 #[serde(rename = "type")]
802 pub drop_cap_type: ParagraphDropCapType,
803 #[serde(skip_serializing_if = "Option::is_none")]
804 pub lines: Option<i64>,
805 #[serde(skip_serializing_if = "Option::is_none")]
806 pub wrap: Option<String>,
807 #[serde(skip_serializing_if = "Option::is_none")]
808 pub horizontal_anchor: Option<String>,
809 #[serde(skip_serializing_if = "Option::is_none")]
810 pub vertical_anchor: Option<String>,
811 #[serde(skip_serializing_if = "Option::is_none")]
812 pub x_twips: Option<i64>,
813 #[serde(skip_serializing_if = "Option::is_none")]
814 pub y_twips: Option<i64>,
815 #[serde(skip_serializing_if = "Option::is_none")]
816 pub horizontal_space_twips: Option<i64>,
817 #[serde(skip_serializing_if = "Option::is_none")]
818 pub vertical_space_twips: Option<i64>,
819}
820
821#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
822#[serde(rename_all = "camelCase")]
823pub enum ParagraphTextAlignment {
824 Auto,
825 Top,
826 Center,
827 Baseline,
828 Bottom,
829}
830
831#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
833#[serde(rename_all = "camelCase")]
834pub struct ParagraphStyle {
835 #[serde(skip_serializing_if = "Option::is_none")]
836 pub source_before_auto_spacing: Option<bool>,
837 #[serde(skip_serializing_if = "Option::is_none")]
838 pub source_after_auto_spacing: Option<bool>,
839 #[serde(skip_serializing_if = "Option::is_none")]
840 pub align: Option<ParagraphAlignment>,
841 #[serde(skip_serializing_if = "Option::is_none")]
842 pub snap_to_grid: Option<bool>,
843 #[serde(skip_serializing_if = "Option::is_none")]
844 pub source_snap_to_grid: Option<bool>,
845 #[serde(skip_serializing_if = "Option::is_none")]
846 pub source_has_snap_to_grid: Option<bool>,
847 #[serde(skip_serializing_if = "Option::is_none")]
848 pub source_inherited_snap_to_grid: Option<bool>,
849 #[serde(skip_serializing_if = "Option::is_none")]
850 pub source_table_snap_to_grid: Option<bool>,
851 #[serde(skip_serializing_if = "Option::is_none")]
852 pub text_alignment: Option<ParagraphTextAlignment>,
853 #[serde(skip_serializing_if = "Option::is_none")]
854 pub source_text_alignment: Option<ParagraphTextAlignment>,
855 #[serde(skip_serializing_if = "Option::is_none")]
856 pub source_has_text_alignment: Option<bool>,
857 #[serde(skip_serializing_if = "Option::is_none")]
858 pub source_inherited_text_alignment: Option<ParagraphTextAlignment>,
859 #[serde(skip_serializing_if = "Option::is_none")]
860 pub source_table_text_alignment: Option<ParagraphTextAlignment>,
861 #[serde(skip_serializing_if = "Option::is_none")]
862 pub heading_level: Option<HeadingLevel>,
863 #[serde(skip_serializing_if = "Option::is_none")]
864 pub style_id: Option<String>,
865 #[serde(skip_serializing_if = "Option::is_none")]
866 pub style_name: Option<String>,
867 #[serde(skip_serializing_if = "Option::is_none")]
868 pub numbering: Option<ParagraphNumbering>,
869 #[serde(skip_serializing_if = "Option::is_none")]
870 pub spacing: Option<ParagraphSpacing>,
871 #[serde(skip_serializing_if = "Option::is_none")]
872 pub indent: Option<ParagraphIndent>,
873 #[serde(skip_serializing_if = "Option::is_none")]
874 pub background_color: Option<String>,
875 #[serde(skip_serializing_if = "Option::is_none")]
876 pub borders: Option<ParagraphBorderSet>,
877 #[serde(skip_serializing_if = "Option::is_none")]
878 pub tab_stops: Option<Vec<ParagraphTabStop>>,
879 #[serde(skip_serializing_if = "Option::is_none")]
880 pub contextual_spacing: Option<bool>,
881 #[serde(skip_serializing_if = "Option::is_none")]
882 pub keep_next: Option<bool>,
883 #[serde(skip_serializing_if = "Option::is_none")]
884 pub keep_lines: Option<bool>,
885 #[serde(skip_serializing_if = "Option::is_none")]
886 pub widow_control: Option<bool>,
887 #[serde(skip_serializing_if = "Option::is_none")]
888 pub page_break_before: Option<bool>,
889 #[serde(skip_serializing_if = "Option::is_none")]
890 pub drop_cap: Option<ParagraphDropCap>,
891}
892
893#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
895#[serde(rename_all = "camelCase")]
896pub struct ParagraphSourceTextPatchRun {
897 #[serde(skip_serializing_if = "Option::is_none")]
898 pub style: Option<SharedTextStyle>,
899 #[serde(skip_serializing_if = "Option::is_none")]
900 pub link: Option<String>,
901 #[serde(skip_serializing_if = "Option::is_none")]
902 pub note_reference: Option<NoteReference>,
903}
904
905#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
906#[serde(rename_all = "camelCase")]
907pub struct ParagraphSourceTextPatch {
908 pub runs: Vec<ParagraphSourceTextPatchRun>,
909}
910
911#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
913#[serde(rename_all = "camelCase")]
914pub struct ParagraphMarkFormattingSource {
915 #[serde(skip_serializing_if = "Option::is_none")]
916 pub default_style: Option<SharedTextStyle>,
917 #[serde(skip_serializing_if = "Option::is_none")]
918 pub character_style: Option<SharedTextStyle>,
919 #[serde(skip_serializing_if = "Option::is_none")]
920 pub direct_style: Option<SharedTextStyle>,
921}
922
923#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
925#[serde(rename_all = "camelCase")]
926pub struct ParagraphNode {
927 #[serde(default, skip_serializing_if = "Option::is_none")]
928 pub block_id: Option<String>,
929 #[serde(default = "default_paragraph_node_type", rename = "type")]
930 pub r#type: ParagraphNodeType,
931 pub children: Vec<ParagraphChildNode>,
932 #[serde(skip_serializing_if = "Option::is_none")]
933 pub style: Option<SharedParagraphStyle>,
934 #[serde(skip_serializing_if = "Option::is_none")]
935 pub paragraph_mark_style: Option<SharedTextStyle>,
936 #[serde(skip_serializing_if = "Option::is_none")]
937 pub source_paragraph_mark_style: Option<SharedTextStyle>,
938 #[serde(skip_serializing_if = "Option::is_none")]
939 pub source_paragraph_mark_formatting: Option<ParagraphMarkFormattingSource>,
940 #[serde(skip_serializing_if = "Option::is_none")]
941 pub source_paragraph_mark_properties_xml: Option<String>,
942 #[serde(skip_serializing_if = "Option::is_none")]
943 pub paragraph_mark_deleted: Option<bool>,
944 #[serde(skip_serializing_if = "Option::is_none")]
945 pub source_xml: Option<String>,
946 #[serde(skip_serializing_if = "Option::is_none")]
947 pub source_text_patch: Option<ParagraphSourceTextPatch>,
948 #[serde(skip_serializing_if = "Option::is_none")]
951 pub source_run_provenance: Option<ParagraphSourceTextPatch>,
952}
953
954#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
956pub enum ParagraphNodeType {
957 #[serde(rename = "paragraph")]
958 Paragraph,
959}
960
961#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
963#[serde(rename_all = "camelCase")]
964pub struct TableBoxSpacing {
965 #[serde(skip_serializing_if = "Option::is_none")]
966 pub top_twips: Option<i64>,
967 #[serde(skip_serializing_if = "Option::is_none")]
968 pub right_twips: Option<i64>,
969 #[serde(skip_serializing_if = "Option::is_none")]
970 pub bottom_twips: Option<i64>,
971 #[serde(skip_serializing_if = "Option::is_none")]
972 pub left_twips: Option<i64>,
973}
974
975#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
977#[serde(rename_all = "camelCase")]
978pub struct TableBorderStyle {
979 #[serde(rename = "type")]
980 pub border_type: String,
981 #[serde(skip_serializing_if = "Option::is_none")]
982 pub color: Option<String>,
983 #[serde(skip_serializing_if = "Option::is_none")]
984 pub size_eighth_pt: Option<f64>,
985}
986
987#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
989#[serde(rename_all = "camelCase")]
990pub struct TableBorderSet {
991 #[serde(skip_serializing_if = "Option::is_none")]
992 pub top: Option<TableBorderStyle>,
993 #[serde(skip_serializing_if = "Option::is_none")]
994 pub right: Option<TableBorderStyle>,
995 #[serde(skip_serializing_if = "Option::is_none")]
996 pub bottom: Option<TableBorderStyle>,
997 #[serde(skip_serializing_if = "Option::is_none")]
998 pub left: Option<TableBorderStyle>,
999 #[serde(skip_serializing_if = "Option::is_none")]
1000 pub inside_h: Option<TableBorderStyle>,
1001 #[serde(skip_serializing_if = "Option::is_none")]
1002 pub inside_v: Option<TableBorderStyle>,
1003 #[serde(skip_serializing_if = "Option::is_none")]
1004 pub tl2br: Option<TableBorderStyle>,
1005 #[serde(skip_serializing_if = "Option::is_none")]
1006 pub tr2bl: Option<TableBorderStyle>,
1007}
1008
1009#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1011#[serde(rename_all = "camelCase")]
1012pub enum TableCellVerticalAlign {
1013 Top,
1014 Center,
1015 Bottom,
1016}
1017
1018#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1020#[serde(tag = "type", rename_all = "camelCase")]
1021pub enum TablePreferredWidth {
1022 Dxa { value: f64 },
1023 Pct { value: f64 },
1024 Auto,
1025 Nil,
1026}
1027
1028#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1030#[serde(rename_all = "camelCase")]
1031pub struct TableWidthSource {
1032 #[serde(skip_serializing_if = "Option::is_none")]
1033 pub preferred_width: Option<TablePreferredWidth>,
1034 #[serde(skip_serializing_if = "Option::is_none")]
1035 pub width_twips: Option<i64>,
1036 #[serde(skip_serializing_if = "Option::is_none")]
1037 pub inherited_preferred_width: Option<TablePreferredWidth>,
1038}
1039
1040#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1041#[serde(rename_all = "camelCase")]
1042pub enum TableAlignment {
1043 Left,
1044 Center,
1045 Right,
1046}
1047
1048#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1050#[serde(rename_all = "camelCase")]
1051pub struct TableCellStyle {
1052 #[serde(skip_serializing_if = "Option::is_none")]
1053 pub background_color: Option<String>,
1054 #[serde(skip_serializing_if = "Option::is_none")]
1055 pub grid_span: Option<i64>,
1056 #[serde(skip_serializing_if = "Option::is_none")]
1057 pub row_span: Option<i64>,
1058 #[serde(skip_serializing_if = "Option::is_none")]
1059 pub v_merge_continuation: Option<bool>,
1060 #[serde(skip_serializing_if = "Option::is_none")]
1061 pub width_twips: Option<i64>,
1062 #[serde(skip_serializing_if = "Option::is_none")]
1063 pub preferred_width: Option<TablePreferredWidth>,
1064 #[serde(skip_serializing_if = "Option::is_none")]
1065 pub source_width: Option<TableWidthSource>,
1066 #[serde(skip_serializing_if = "Option::is_none")]
1067 pub margin_twips: Option<TableBoxSpacing>,
1068 #[serde(skip_serializing_if = "Option::is_none")]
1069 pub vertical_align: Option<TableCellVerticalAlign>,
1070 #[serde(skip_serializing_if = "Option::is_none")]
1071 pub text_direction: Option<String>,
1072 #[serde(skip_serializing_if = "Option::is_none")]
1073 pub source_text_direction: Option<String>,
1074 #[serde(skip_serializing_if = "Option::is_none")]
1075 pub no_wrap: Option<bool>,
1076 #[serde(skip_serializing_if = "Option::is_none")]
1077 pub source_no_wrap: Option<bool>,
1078 #[serde(skip_serializing_if = "Option::is_none")]
1079 pub borders: Option<TableBorderSet>,
1080}
1081
1082#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1084#[serde(untagged)]
1085pub enum TableCellContentNode {
1086 Paragraph(ParagraphNode),
1087 Table(Box<TableNode>),
1088}
1089
1090#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1092#[serde(rename_all = "camelCase")]
1093pub struct TableCellNode {
1094 #[serde(default = "default_table_cell_node_type", rename = "type")]
1095 pub r#type: TableCellNodeType,
1096 pub nodes: Vec<TableCellContentNode>,
1097 #[serde(skip_serializing_if = "Option::is_none")]
1098 pub style: Option<TableCellStyle>,
1099}
1100
1101#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1103pub enum TableCellNodeType {
1104 #[serde(rename = "table-cell")]
1105 TableCell,
1106}
1107
1108#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1110pub enum TableRowHeightRule {
1111 #[serde(rename = "auto")]
1112 Auto,
1113 #[serde(rename = "atLeast")]
1114 AtLeast,
1115 #[serde(rename = "exact")]
1116 Exact,
1117}
1118
1119#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1121#[serde(rename_all = "camelCase")]
1122pub struct TableRowGeometrySource {
1123 #[serde(skip_serializing_if = "Option::is_none")]
1124 pub grid_before: Option<i64>,
1125 #[serde(skip_serializing_if = "Option::is_none")]
1126 pub grid_after: Option<i64>,
1127 #[serde(skip_serializing_if = "Option::is_none")]
1128 pub width_before: Option<TablePreferredWidth>,
1129 #[serde(skip_serializing_if = "Option::is_none")]
1130 pub width_after: Option<TablePreferredWidth>,
1131}
1132
1133#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1135#[serde(rename_all = "camelCase")]
1136pub struct TableRowStyle {
1137 #[serde(skip_serializing_if = "Option::is_none")]
1138 pub grid_before: Option<i64>,
1139 #[serde(skip_serializing_if = "Option::is_none")]
1140 pub grid_after: Option<i64>,
1141 #[serde(skip_serializing_if = "Option::is_none")]
1142 pub width_before: Option<TablePreferredWidth>,
1143 #[serde(skip_serializing_if = "Option::is_none")]
1144 pub width_after: Option<TablePreferredWidth>,
1145 #[serde(skip_serializing_if = "Option::is_none")]
1146 pub source_row_geometry: Option<TableRowGeometrySource>,
1147 #[serde(skip_serializing_if = "Option::is_none")]
1148 pub background_color: Option<String>,
1149 #[serde(skip_serializing_if = "Option::is_none")]
1150 pub height_twips: Option<i64>,
1151 #[serde(skip_serializing_if = "Option::is_none")]
1152 pub height_rule: Option<TableRowHeightRule>,
1153 #[serde(skip_serializing_if = "Option::is_none")]
1154 pub cant_split: Option<bool>,
1155 #[serde(skip_serializing_if = "Option::is_none")]
1156 pub is_header: Option<bool>,
1157}
1158
1159#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1161#[serde(rename_all = "camelCase")]
1162pub struct TableRowNode {
1163 #[serde(default = "default_table_row_node_type", rename = "type")]
1164 pub r#type: TableRowNodeType,
1165 pub cells: Vec<TableCellNode>,
1166 #[serde(skip_serializing_if = "Option::is_none")]
1167 pub style: Option<TableRowStyle>,
1168}
1169
1170#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1172pub enum TableRowNodeType {
1173 #[serde(rename = "table-row")]
1174 TableRow,
1175}
1176
1177#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1179pub enum TableLayout {
1180 #[serde(rename = "fixed")]
1181 Fixed,
1182 #[serde(rename = "autofit")]
1183 Autofit,
1184}
1185
1186#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1188#[serde(rename_all = "camelCase")]
1189pub struct TableFloating {
1190 #[serde(skip_serializing_if = "Option::is_none")]
1191 pub x_twips: Option<i64>,
1192 #[serde(skip_serializing_if = "Option::is_none")]
1193 pub y_twips: Option<i64>,
1194 #[serde(skip_serializing_if = "Option::is_none")]
1195 pub left_from_text_twips: Option<i64>,
1196 #[serde(skip_serializing_if = "Option::is_none")]
1197 pub right_from_text_twips: Option<i64>,
1198 #[serde(skip_serializing_if = "Option::is_none")]
1199 pub top_from_text_twips: Option<i64>,
1200 #[serde(skip_serializing_if = "Option::is_none")]
1201 pub bottom_from_text_twips: Option<i64>,
1202 #[serde(skip_serializing_if = "Option::is_none")]
1203 pub horizontal_anchor: Option<String>,
1204 #[serde(skip_serializing_if = "Option::is_none")]
1205 pub vertical_anchor: Option<String>,
1206 #[serde(skip_serializing_if = "Option::is_none")]
1207 pub horizontal_align: Option<ImageHorizontalAlign>,
1208 #[serde(skip_serializing_if = "Option::is_none")]
1209 pub vertical_align: Option<ImageVerticalAlign>,
1210}
1211
1212#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1214#[serde(rename_all = "camelCase")]
1215pub struct TableStyle {
1216 #[serde(skip_serializing_if = "Option::is_none")]
1217 pub style_id: Option<String>,
1218 #[serde(skip_serializing_if = "Option::is_none")]
1219 pub source_style_id: Option<String>,
1220 #[serde(skip_serializing_if = "Option::is_none")]
1221 pub width_twips: Option<i64>,
1222 #[serde(skip_serializing_if = "Option::is_none")]
1223 pub preferred_width: Option<TablePreferredWidth>,
1224 #[serde(skip_serializing_if = "Option::is_none")]
1225 pub source_width: Option<TableWidthSource>,
1226 #[serde(skip_serializing_if = "Option::is_none")]
1227 pub alignment: Option<TableAlignment>,
1228 #[serde(skip_serializing_if = "Option::is_none")]
1229 pub source_alignment: Option<TableAlignment>,
1230 #[serde(skip_serializing_if = "Option::is_none")]
1231 pub source_inherited_alignment: Option<TableAlignment>,
1232 #[serde(skip_serializing_if = "Option::is_none")]
1233 pub bidi_visual: Option<bool>,
1234 #[serde(skip_serializing_if = "Option::is_none")]
1235 pub source_bidi_visual: Option<bool>,
1236 #[serde(skip_serializing_if = "Option::is_none")]
1237 pub source_inherited_bidi_visual: Option<bool>,
1238 #[serde(skip_serializing_if = "Option::is_none")]
1239 pub indent_twips: Option<i64>,
1240 #[serde(skip_serializing_if = "Option::is_none")]
1241 pub layout: Option<TableLayout>,
1242 #[serde(skip_serializing_if = "Option::is_none")]
1243 pub cell_spacing_twips: Option<i64>,
1244 #[serde(skip_serializing_if = "Option::is_none")]
1245 pub cell_margin_twips: Option<TableBoxSpacing>,
1246 #[serde(skip_serializing_if = "Option::is_none")]
1247 pub column_widths_twips: Option<Vec<i64>>,
1248 #[serde(skip_serializing_if = "Option::is_none")]
1251 pub collapsed_grid_columns: Option<Vec<usize>>,
1252 #[serde(skip_serializing_if = "Option::is_none")]
1253 pub borders: Option<TableBorderSet>,
1254 #[serde(skip_serializing_if = "Option::is_none")]
1255 pub floating: Option<TableFloating>,
1256}
1257
1258#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1260#[serde(rename_all = "camelCase")]
1261pub struct TableSourceTextPatch {
1262 pub source_paragraph_xml: String,
1263 pub paragraph: ParagraphNode,
1264}
1265
1266#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1268#[serde(rename_all = "camelCase")]
1269pub struct TableNode {
1270 #[serde(default, skip_serializing_if = "Option::is_none")]
1271 pub block_id: Option<String>,
1272 #[serde(default = "default_table_node_type", rename = "type")]
1273 pub r#type: TableNodeType,
1274 pub rows: Vec<TableRowNode>,
1275 #[serde(skip_serializing_if = "Option::is_none")]
1276 pub style: Option<TableStyle>,
1277 #[serde(skip_serializing_if = "Option::is_none")]
1278 pub source_xml: Option<String>,
1279 #[serde(skip_serializing_if = "Option::is_none")]
1280 pub source_text_patches: Option<Vec<TableSourceTextPatch>>,
1281}
1282
1283#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1285pub enum TableNodeType {
1286 #[serde(rename = "table")]
1287 Table,
1288}
1289
1290#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1292#[serde(untagged)]
1293pub enum DocNode {
1294 Paragraph(ParagraphNode),
1295 Table(TableNode),
1296}
1297
1298#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1300#[serde(rename_all = "camelCase")]
1301pub struct HeaderSection {
1302 pub part_name: String,
1303 #[serde(skip_serializing_if = "Option::is_none")]
1304 pub reference_type: Option<String>,
1305 pub nodes: Vec<DocNode>,
1306}
1307
1308#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1310#[serde(rename_all = "camelCase")]
1311pub struct FooterSection {
1312 pub part_name: String,
1313 #[serde(skip_serializing_if = "Option::is_none")]
1314 pub reference_type: Option<String>,
1315 pub nodes: Vec<DocNode>,
1316}
1317
1318#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1320#[serde(rename_all = "camelCase")]
1321pub struct DocumentSection {
1322 pub start_node_index: i64,
1323 #[serde(skip_serializing_if = "Option::is_none")]
1324 pub section_properties_xml: Option<String>,
1325 pub header_sections: Vec<HeaderSection>,
1326 pub footer_sections: Vec<FooterSection>,
1327}
1328
1329#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1331#[serde(rename_all = "camelCase")]
1332pub struct ParagraphStyleDefinition {
1333 pub id: String,
1334 pub name: String,
1335 #[serde(skip_serializing_if = "Option::is_none")]
1336 pub based_on_id: Option<String>,
1337 #[serde(skip_serializing_if = "Option::is_none")]
1338 pub next_style_id: Option<String>,
1339 #[serde(skip_serializing_if = "Option::is_none")]
1340 pub align: Option<ParagraphAlignment>,
1341 #[serde(skip_serializing_if = "Option::is_none")]
1342 pub snap_to_grid: Option<bool>,
1343 #[serde(skip_serializing_if = "Option::is_none")]
1344 pub source_has_snap_to_grid: Option<bool>,
1345 #[serde(skip_serializing_if = "Option::is_none")]
1346 pub text_alignment: Option<ParagraphTextAlignment>,
1347 #[serde(skip_serializing_if = "Option::is_none")]
1348 pub source_has_text_alignment: Option<bool>,
1349 #[serde(skip_serializing_if = "Option::is_none")]
1350 pub heading_level: Option<HeadingLevel>,
1351 #[serde(skip_serializing_if = "Option::is_none")]
1352 pub numbering: Option<ParagraphNumbering>,
1353 #[serde(skip_serializing_if = "Option::is_none")]
1354 pub spacing: Option<ParagraphSpacing>,
1355 #[serde(skip_serializing_if = "Option::is_none")]
1356 pub indent: Option<ParagraphIndent>,
1357 #[serde(skip_serializing_if = "Option::is_none")]
1358 pub background_color: Option<String>,
1359 #[serde(skip_serializing_if = "Option::is_none")]
1360 pub borders: Option<ParagraphBorderSet>,
1361 #[serde(skip_serializing_if = "Option::is_none")]
1362 pub tab_stops: Option<Vec<ParagraphTabStop>>,
1363 #[serde(skip_serializing_if = "Option::is_none")]
1364 pub contextual_spacing: Option<bool>,
1365 #[serde(skip_serializing_if = "Option::is_none")]
1366 pub keep_next: Option<bool>,
1367 #[serde(skip_serializing_if = "Option::is_none")]
1368 pub keep_lines: Option<bool>,
1369 #[serde(skip_serializing_if = "Option::is_none")]
1370 pub widow_control: Option<bool>,
1371 #[serde(skip_serializing_if = "Option::is_none")]
1372 pub page_break_before: Option<bool>,
1373 #[serde(skip_serializing_if = "Option::is_none")]
1374 pub run_style: Option<TextStyle>,
1375 #[serde(skip_serializing_if = "Option::is_none")]
1376 pub ui_priority: Option<i64>,
1377 #[serde(skip_serializing_if = "Option::is_none")]
1378 pub is_default: Option<bool>,
1379 #[serde(skip_serializing_if = "Option::is_none")]
1380 pub is_primary: Option<bool>,
1381}
1382
1383#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1385pub enum NumberingLevelSuffix {
1386 #[serde(rename = "tab")]
1387 Tab,
1388 #[serde(rename = "space")]
1389 Space,
1390 #[serde(rename = "nothing")]
1391 Nothing,
1392}
1393
1394#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1396#[serde(rename_all = "camelCase")]
1397pub struct NumberingLevelDefinition {
1398 pub ilvl: i64,
1399 #[serde(skip_serializing_if = "Option::is_none")]
1400 pub start: Option<i64>,
1401 #[serde(skip_serializing_if = "Option::is_none")]
1402 pub format: Option<String>,
1403 #[serde(skip_serializing_if = "Option::is_none")]
1404 pub text: Option<String>,
1405 #[serde(skip_serializing_if = "Option::is_none")]
1406 pub suffix: Option<NumberingLevelSuffix>,
1407 #[serde(skip_serializing_if = "Option::is_none")]
1411 pub lvl_restart: Option<i64>,
1412 #[serde(skip_serializing_if = "Option::is_none")]
1415 pub is_lgl: Option<bool>,
1416 #[serde(skip_serializing_if = "Option::is_none")]
1417 pub indent: Option<ParagraphIndent>,
1418 #[serde(skip_serializing_if = "Option::is_none")]
1419 pub run_style: Option<TextStyle>,
1420 #[serde(skip_serializing_if = "Option::is_none")]
1421 pub bullet_font_family: Option<String>,
1422 #[serde(skip_serializing_if = "Option::is_none")]
1423 pub bullet_color: Option<String>,
1424 #[serde(skip_serializing_if = "Option::is_none")]
1425 pub picture_bullet_id: Option<i64>,
1426 #[serde(skip_serializing_if = "Option::is_none")]
1427 pub picture_bullet: Option<NumberingPictureBulletDefinition>,
1428}
1429
1430#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1432#[serde(rename_all = "camelCase")]
1433pub struct NumberingAbstractDefinition {
1434 pub abstract_num_id: i64,
1435 pub levels: Vec<NumberingLevelDefinition>,
1436}
1437
1438#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1440#[serde(rename_all = "camelCase")]
1441pub struct NumberingInstanceDefinition {
1442 pub num_id: i64,
1443 pub abstract_num_id: i64,
1444 #[serde(skip_serializing_if = "Option::is_none")]
1445 pub level_start_overrides: Option<HashMap<String, i64>>,
1446 #[serde(skip_serializing_if = "Option::is_none")]
1447 pub level_overrides: Option<Vec<NumberingLevelDefinition>>,
1448}
1449
1450#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1452#[serde(rename_all = "camelCase")]
1453pub struct NumberingDefinitionSet {
1454 pub abstracts: Vec<NumberingAbstractDefinition>,
1455 pub instances: Vec<NumberingInstanceDefinition>,
1456}
1457
1458#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1460#[serde(rename_all = "camelCase")]
1461pub struct NumberingPictureBulletDefinition {
1462 pub num_pic_bullet_id: i64,
1463 #[serde(skip_serializing_if = "Option::is_none")]
1464 pub src: Option<String>,
1465 #[serde(skip_serializing_if = "Option::is_none")]
1466 pub width_px: Option<f64>,
1467 #[serde(skip_serializing_if = "Option::is_none")]
1468 pub height_px: Option<f64>,
1469 #[serde(skip_serializing_if = "Option::is_none")]
1470 pub part_name: Option<String>,
1471 #[serde(skip_serializing_if = "Option::is_none")]
1472 pub content_type: Option<String>,
1473}
1474
1475#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1477#[serde(rename_all = "camelCase")]
1478pub struct DocumentNoteDefinition {
1479 pub id: i64,
1480 pub text: String,
1481 #[serde(skip_serializing_if = "Option::is_none")]
1482 pub nodes: Option<Vec<DocNode>>,
1483}
1484
1485#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1487#[serde(rename_all = "camelCase")]
1488pub struct DocumentCommentDefinition {
1489 #[serde(default, skip_serializing_if = "Option::is_none")]
1490 pub nodes: Option<Vec<DocNode>>,
1491 pub id: i64,
1492 #[serde(skip_serializing_if = "Option::is_none")]
1493 pub author: Option<String>,
1494 #[serde(skip_serializing_if = "Option::is_none")]
1495 pub initials: Option<String>,
1496 #[serde(skip_serializing_if = "Option::is_none")]
1497 pub date: Option<String>,
1498 pub text: String,
1499 #[serde(skip_serializing_if = "Option::is_none")]
1500 pub parent_id: Option<i64>,
1501 #[serde(skip_serializing_if = "Option::is_none")]
1502 pub resolved: Option<bool>,
1503 #[serde(skip_serializing_if = "Option::is_none")]
1504 pub source_xml: Option<String>,
1505 #[serde(skip_serializing_if = "Option::is_none")]
1506 pub extended_paragraph_id: Option<String>,
1507 #[serde(skip_serializing_if = "Option::is_none")]
1508 pub source_resolved: Option<bool>,
1509 #[serde(skip_serializing_if = "Option::is_none")]
1510 pub resolution_dirty: Option<bool>,
1511 #[serde(skip_serializing_if = "Option::is_none")]
1512 pub is_new: Option<bool>,
1513}
1514
1515#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1517#[serde(rename_all = "camelCase")]
1518pub struct DocumentCompatibilitySettings {
1519 #[serde(skip_serializing_if = "Option::is_none")]
1520 pub adjust_line_height_in_table: Option<bool>,
1521 #[serde(skip_serializing_if = "Option::is_none")]
1522 pub no_leading: Option<bool>,
1523 #[serde(
1524 rename = "suppressTopSpacingWP",
1525 skip_serializing_if = "Option::is_none"
1526 )]
1527 pub suppress_top_spacing_wp: Option<bool>,
1528 #[serde(
1529 rename = "truncateFontHeightsLikeWP6",
1530 skip_serializing_if = "Option::is_none"
1531 )]
1532 pub truncate_font_heights_like_wp6: Option<bool>,
1533 #[serde(skip_serializing_if = "Option::is_none")]
1534 pub no_extra_line_spacing: Option<bool>,
1535 #[serde(rename = "spaceForUL", skip_serializing_if = "Option::is_none")]
1536 pub space_for_ul: Option<bool>,
1537 #[serde(skip_serializing_if = "Option::is_none")]
1538 pub suppress_bottom_spacing: Option<bool>,
1539 #[serde(skip_serializing_if = "Option::is_none")]
1540 pub compatibility_mode: Option<i64>,
1541 #[serde(
1542 rename = "enableOpenTypeFeatures",
1543 skip_serializing_if = "Option::is_none"
1544 )]
1545 pub enable_open_type_features: Option<bool>,
1546 #[serde(skip_serializing_if = "Option::is_none")]
1547 pub suppress_spacing_before_after_page_break: Option<bool>,
1548 #[serde(skip_serializing_if = "Option::is_none")]
1549 pub use_printer_metrics: Option<bool>,
1550 #[serde(skip_serializing_if = "Option::is_none")]
1551 pub use_fixed_html_paragraph_spacing: Option<bool>,
1552 #[serde(skip_serializing_if = "Option::is_none")]
1553 pub do_not_break_wrapped_tables: Option<bool>,
1554 #[serde(skip_serializing_if = "Option::is_none")]
1555 pub do_not_break_constrained_forced_table: Option<bool>,
1556 #[serde(skip_serializing_if = "Option::is_none")]
1557 pub even_and_odd_headers: Option<bool>,
1558}
1559
1560#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1562#[serde(rename_all = "camelCase")]
1563pub struct DocModelMetadata {
1564 #[serde(default, skip_serializing_if = "Option::is_none")]
1565 pub document_id: Option<String>,
1566 #[serde(default, skip_serializing_if = "Option::is_none")]
1567 pub source_part_names: Option<std::collections::BTreeMap<String, String>>,
1568 pub source_parts: i64,
1569 pub warnings: Vec<String>,
1570 #[serde(skip_serializing_if = "Option::is_none")]
1571 pub document_page_count: Option<i64>,
1572 #[serde(skip_serializing_if = "Option::is_none")]
1573 pub document_open_tag: Option<String>,
1574 #[serde(skip_serializing_if = "Option::is_none")]
1575 pub document_background_color: Option<String>,
1576 #[serde(skip_serializing_if = "Option::is_none")]
1577 pub section_properties_xml: Option<String>,
1578 #[serde(skip_serializing_if = "Option::is_none")]
1579 pub sections: Option<Vec<DocumentSection>>,
1580 pub header_sections: Vec<HeaderSection>,
1581 pub footer_sections: Vec<FooterSection>,
1582 pub paragraph_styles: Vec<ParagraphStyleDefinition>,
1583 #[serde(skip_serializing_if = "Option::is_none")]
1584 pub default_paragraph_style_id: Option<String>,
1585 #[serde(skip_serializing_if = "Option::is_none")]
1586 pub default_tab_stop_twips: Option<i64>,
1587 #[serde(skip_serializing_if = "Option::is_none")]
1588 pub document_settings_imported: Option<bool>,
1589 #[serde(skip_serializing_if = "Option::is_none")]
1590 pub line_spacing_compatibility_imported: Option<bool>,
1591 #[serde(skip_serializing_if = "Option::is_none")]
1592 pub numbering_definitions: Option<NumberingDefinitionSet>,
1593 #[serde(skip_serializing_if = "Option::is_none")]
1594 pub compatibility: Option<DocumentCompatibilitySettings>,
1595 #[serde(skip_serializing_if = "Option::is_none")]
1596 pub footnotes: Option<Vec<DocumentNoteDefinition>>,
1597 #[serde(skip_serializing_if = "Option::is_none")]
1598 pub endnotes: Option<Vec<DocumentNoteDefinition>>,
1599 #[serde(skip_serializing_if = "Option::is_none")]
1600 pub comments: Option<Vec<DocumentCommentDefinition>>,
1601}
1602
1603#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1605#[serde(rename_all = "camelCase")]
1606pub struct DocModel {
1607 pub nodes: Vec<DocNode>,
1608 pub metadata: DocModelMetadata,
1609}
1610
1611#[cfg(test)]
1612mod deserialize_tests {
1613 use super::{DocModel, DocNode, HeadingLevel, ParagraphAlignment};
1614
1615 #[test]
1616 fn deserializes_minimal_js_doc_model() {
1617 let json = r#"{"nodes":[{"type":"paragraph","children":[{"type":"text","text":"Hi"}]}],"metadata":{"sourceParts":1,"warnings":[],"headerSections":[],"footerSections":[],"paragraphStyles":[]}}"#;
1618 let model: DocModel = serde_json::from_str(json).expect("should deserialize");
1619 assert_eq!(model.nodes.len(), 1);
1620 }
1621
1622 #[test]
1623 fn deserializes_heading_level_two() {
1624 let json = r#"{"type":"paragraph","style":{"headingLevel":2},"children":[{"type":"text","text":"Added"}]}"#;
1625 let node: DocNode = serde_json::from_str(json).expect("heading level 2");
1626 let DocNode::Paragraph(paragraph) = node else {
1627 panic!("expected paragraph");
1628 };
1629 assert_eq!(
1630 paragraph.style.and_then(|style| style.heading_level),
1631 Some(HeadingLevel::Two)
1632 );
1633 }
1634
1635 #[test]
1636 fn deserializes_align_center() {
1637 let json = r#"{"type":"paragraph","style":{"align":"center"},"children":[{"type":"text","text":"Added"}]}"#;
1638 let node: DocNode = serde_json::from_str(json).expect("align center");
1639 let DocNode::Paragraph(paragraph) = node else {
1640 panic!("expected paragraph");
1641 };
1642 assert_eq!(
1643 paragraph.style.and_then(|style| style.align),
1644 Some(ParagraphAlignment::Center)
1645 );
1646 }
1647}
1648
1649#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
1651#[serde(transparent)]
1652pub struct SharedParagraphStyle(std::sync::Arc<ParagraphStyle>);
1653
1654impl SharedParagraphStyle {
1655 pub fn into_owned(self) -> ParagraphStyle {
1656 std::sync::Arc::unwrap_or_clone(self.0)
1657 }
1658}
1659
1660impl From<ParagraphStyle> for SharedParagraphStyle {
1661 fn from(style: ParagraphStyle) -> Self {
1662 Self(std::sync::Arc::new(style))
1663 }
1664}
1665
1666impl std::ops::Deref for SharedParagraphStyle {
1667 type Target = ParagraphStyle;
1668
1669 fn deref(&self) -> &ParagraphStyle {
1670 &self.0
1671 }
1672}
1673
1674impl std::ops::DerefMut for SharedParagraphStyle {
1675 fn deref_mut(&mut self) -> &mut ParagraphStyle {
1676 std::sync::Arc::make_mut(&mut self.0)
1677 }
1678}
1679