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 chart_part_name: Option<String>,
458 #[serde(default, skip_serializing_if = "Option::is_none")]
459 pub chart_data: Option<Box<crate::ChartData>>,
460 #[serde(default, skip_serializing_if = "Option::is_none")]
461 pub paint_bounds: Option<Box<ImagePaintBounds>>,
462 #[serde(default, skip_serializing_if = "Option::is_none")]
463 pub math_ml: Option<String>,
464 #[serde(default, skip_serializing_if = "Option::is_none")]
465 pub content_nodes: Option<Vec<DocNode>>,
466 #[serde(default, skip_serializing_if = "Option::is_none")]
467 pub semantic_kind: Option<String>,
468 #[serde(default, skip_serializing_if = "Option::is_none")]
469 pub block_id: Option<String>,
470 #[serde(default = "default_image_run_type", rename = "type")]
471 pub r#type: ImageRunNodeType,
472 #[serde(skip_serializing_if = "Option::is_none")]
473 pub src: Option<String>,
474 #[serde(skip_serializing_if = "Option::is_none")]
475 pub alt: Option<String>,
476 #[serde(skip_serializing_if = "Option::is_none")]
477 pub width_px: Option<f64>,
478 #[serde(skip_serializing_if = "Option::is_none")]
479 pub height_px: Option<f64>,
480 #[serde(skip_serializing_if = "Option::is_none")]
481 pub part_name: Option<String>,
482 #[serde(skip_serializing_if = "Option::is_none")]
483 pub content_type: Option<String>,
484 #[serde(default, skip_serializing_if = "Option::is_none")]
485 pub data: Option<Vec<u8>>,
486 #[serde(skip_serializing_if = "Option::is_none")]
487 pub source_xml: Option<String>,
488 #[serde(skip_serializing_if = "Option::is_none")]
489 pub crop: Option<ImageCrop>,
490 #[serde(skip_serializing_if = "Option::is_none")]
491 pub css_filter: Option<String>,
492 #[serde(skip_serializing_if = "Option::is_none")]
493 pub css_opacity: Option<f64>,
494 #[serde(skip_serializing_if = "Option::is_none")]
495 pub floating: Option<ImageFloating>,
496 #[serde(skip_serializing_if = "Option::is_none")]
497 pub synthetic_text_box: Option<bool>,
498 #[serde(skip_serializing_if = "Option::is_none")]
499 pub text_box_text: Option<String>,
500}
501
502#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
504pub enum ImageRunNodeType {
505 #[serde(rename = "image")]
506 Image,
507}
508
509#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
511#[serde(rename_all = "camelCase")]
512pub enum FormFieldType {
513 #[serde(rename = "checkbox")]
514 Checkbox,
515 #[serde(rename = "text")]
516 Text,
517 #[serde(rename = "date")]
518 Date,
519 #[serde(rename = "dropdown")]
520 Dropdown,
521}
522
523#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
525pub enum FormFieldSourceKind {
526 #[serde(rename = "sdt")]
527 Sdt,
528 #[serde(rename = "legacy")]
529 Legacy,
530}
531
532#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
534#[serde(rename_all = "camelCase")]
535pub struct FormFieldOption {
536 pub display_text: String,
537 #[serde(skip_serializing_if = "Option::is_none")]
538 pub value: Option<String>,
539}
540
541#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
543#[serde(rename_all = "camelCase")]
544pub struct FormFieldTextWidgetSettings {
545 #[serde(skip_serializing_if = "Option::is_none")]
546 pub input_type: Option<String>,
547 #[serde(skip_serializing_if = "Option::is_none")]
548 pub default_text: Option<String>,
549 #[serde(skip_serializing_if = "Option::is_none")]
550 pub max_length: Option<i64>,
551 #[serde(skip_serializing_if = "Option::is_none")]
552 pub text_format: Option<String>,
553}
554
555#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
557#[serde(rename_all = "camelCase")]
558pub struct FormFieldCheckboxWidgetSettings {
559 #[serde(skip_serializing_if = "Option::is_none")]
560 pub default_checked: Option<bool>,
561 #[serde(skip_serializing_if = "Option::is_none")]
562 pub size_mode: Option<FormFieldCheckboxSizeMode>,
563 #[serde(skip_serializing_if = "Option::is_none")]
564 pub size_pt: Option<f64>,
565}
566
567#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
569pub enum FormFieldCheckboxSizeMode {
570 #[serde(rename = "auto")]
571 Auto,
572 #[serde(rename = "exact")]
573 Exact,
574}
575
576#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
578#[serde(rename_all = "camelCase")]
579pub struct FormFieldDropdownWidgetSettings {
580 #[serde(skip_serializing_if = "Option::is_none")]
581 pub default_value: Option<String>,
582}
583
584#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
586#[serde(rename_all = "camelCase")]
587pub struct FormFieldWidgetSettings {
588 #[serde(skip_serializing_if = "Option::is_none")]
589 pub name: Option<String>,
590 #[serde(skip_serializing_if = "Option::is_none")]
591 pub enabled: Option<bool>,
592 #[serde(skip_serializing_if = "Option::is_none")]
593 pub calc_on_exit: Option<bool>,
594 #[serde(skip_serializing_if = "Option::is_none")]
595 pub text: Option<FormFieldTextWidgetSettings>,
596 #[serde(skip_serializing_if = "Option::is_none")]
597 pub checkbox: Option<FormFieldCheckboxWidgetSettings>,
598 #[serde(skip_serializing_if = "Option::is_none")]
599 pub dropdown: Option<FormFieldDropdownWidgetSettings>,
600}
601
602#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
603#[serde(rename_all = "camelCase")]
604pub struct FormFieldSourcePreview {
605 pub relationship_id: String,
606 pub shape_id: String,
607 pub checked: bool,
608 pub image: Box<ImageRunNode>,
609}
610
611#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
613#[serde(rename_all = "camelCase")]
614pub struct FormFieldRunNode {
615 #[serde(default = "default_form_field_run_type", rename = "type")]
616 pub r#type: FormFieldRunNodeType,
617 pub field_type: FormFieldType,
618 #[serde(skip_serializing_if = "Option::is_none")]
619 pub source_kind: Option<FormFieldSourceKind>,
620 #[serde(skip_serializing_if = "Option::is_none")]
621 pub id: Option<i64>,
622 #[serde(skip_serializing_if = "Option::is_none")]
623 pub tag: Option<String>,
624 #[serde(skip_serializing_if = "Option::is_none")]
625 pub title: Option<String>,
626 #[serde(skip_serializing_if = "Option::is_none")]
627 pub placeholder: Option<String>,
628 #[serde(skip_serializing_if = "Option::is_none")]
629 pub checked: Option<bool>,
630 #[serde(skip_serializing_if = "Option::is_none")]
631 pub value: Option<String>,
632 #[serde(skip_serializing_if = "Option::is_none")]
633 pub options: Option<Vec<FormFieldOption>>,
634 #[serde(skip_serializing_if = "Option::is_none")]
635 pub widget: Option<FormFieldWidgetSettings>,
636 #[serde(skip_serializing_if = "Option::is_none")]
637 pub checked_symbol: Option<String>,
638 #[serde(skip_serializing_if = "Option::is_none")]
639 pub unchecked_symbol: Option<String>,
640 #[serde(skip_serializing_if = "Option::is_none")]
641 pub style: Option<SharedTextStyle>,
642 #[serde(skip_serializing_if = "Option::is_none")]
643 pub link: Option<String>,
644 #[serde(skip_serializing_if = "Option::is_none")]
645 pub source_xml: Option<String>,
646 #[serde(default, skip_serializing_if = "Option::is_none")]
647 pub source_preview: Option<Box<FormFieldSourcePreview>>,
648}
649
650#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
652pub enum FormFieldRunNodeType {
653 #[serde(rename = "form-field")]
654 FormField,
655}
656
657#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
659#[serde(untagged)]
660pub enum ParagraphChildNode {
661 Text(TextRunNode),
662 Image(Box<ImageRunNode>),
663 FormField(Box<FormFieldRunNode>),
664}
665
666#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
668#[serde(rename_all = "camelCase")]
669pub struct ParagraphNumbering {
670 pub num_id: i64,
671 pub ilvl: i64,
672}
673
674#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
676pub enum ParagraphLineRule {
677 #[serde(rename = "auto")]
678 Auto,
679 #[serde(rename = "exact")]
680 Exact,
681 #[serde(rename = "atLeast")]
682 AtLeast,
683}
684
685#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
687#[serde(rename_all = "camelCase")]
688pub struct ParagraphSpacing {
689 #[serde(skip_serializing_if = "Option::is_none")]
690 pub before_twips: Option<i64>,
691 #[serde(skip_serializing_if = "Option::is_none")]
692 pub after_twips: Option<i64>,
693 #[serde(skip_serializing_if = "Option::is_none")]
694 pub before_auto_spacing: Option<bool>,
695 #[serde(skip_serializing_if = "Option::is_none")]
696 pub after_auto_spacing: Option<bool>,
697 #[serde(skip_serializing_if = "Option::is_none")]
698 pub line_twips: Option<i64>,
699 #[serde(skip_serializing_if = "Option::is_none")]
700 pub line_rule: Option<ParagraphLineRule>,
701}
702
703#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
705#[serde(rename_all = "camelCase")]
706pub struct ParagraphIndent {
707 #[serde(skip_serializing_if = "Option::is_none")]
708 pub left_twips: Option<i64>,
709 #[serde(skip_serializing_if = "Option::is_none")]
710 pub right_twips: Option<i64>,
711 #[serde(skip_serializing_if = "Option::is_none")]
712 pub first_line_twips: Option<i64>,
713 #[serde(skip_serializing_if = "Option::is_none")]
714 pub hanging_twips: Option<i64>,
715}
716
717#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
719#[serde(rename_all = "camelCase")]
720pub struct ParagraphBorderStyle {
721 #[serde(rename = "type")]
722 pub border_type: String,
723 #[serde(skip_serializing_if = "Option::is_none")]
724 pub color: Option<String>,
725 #[serde(skip_serializing_if = "Option::is_none")]
726 pub size_eighth_pt: Option<f64>,
727 #[serde(skip_serializing_if = "Option::is_none")]
728 pub space_pt: Option<f64>,
729 #[serde(skip_serializing_if = "Option::is_none")]
730 pub frame: Option<bool>,
731 #[serde(skip_serializing_if = "Option::is_none")]
732 pub shadow: Option<bool>,
733}
734
735#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
737#[serde(rename_all = "camelCase")]
738pub struct ParagraphBorderSet {
739 #[serde(skip_serializing_if = "Option::is_none")]
740 pub top: Option<ParagraphBorderStyle>,
741 #[serde(skip_serializing_if = "Option::is_none")]
742 pub right: Option<ParagraphBorderStyle>,
743 #[serde(skip_serializing_if = "Option::is_none")]
744 pub bottom: Option<ParagraphBorderStyle>,
745 #[serde(skip_serializing_if = "Option::is_none")]
746 pub left: Option<ParagraphBorderStyle>,
747 #[serde(skip_serializing_if = "Option::is_none")]
748 pub between: Option<ParagraphBorderStyle>,
749 #[serde(skip_serializing_if = "Option::is_none")]
750 pub bar: Option<ParagraphBorderStyle>,
751}
752
753#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
755#[serde(rename_all = "camelCase")]
756pub enum ParagraphTabStopAlignment {
757 Clear,
758 Left,
759 Center,
760 Right,
761 Decimal,
762 Bar,
763}
764
765#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
767pub enum ParagraphTabStopLeader {
768 #[serde(rename = "none")]
769 LeaderNone,
770 #[serde(rename = "dot")]
771 Dot,
772 #[serde(rename = "hyphen")]
773 Hyphen,
774 #[serde(rename = "underscore")]
775 Underscore,
776 #[serde(rename = "middleDot")]
777 MiddleDot,
778}
779
780#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
782#[serde(rename_all = "camelCase")]
783pub struct ParagraphTabStop {
784 #[serde(skip_serializing_if = "Option::is_none")]
785 pub alignment: Option<ParagraphTabStopAlignment>,
786 #[serde(skip_serializing_if = "Option::is_none")]
787 pub leader: Option<ParagraphTabStopLeader>,
788 #[serde(skip_serializing_if = "Option::is_none")]
789 pub position_twips: Option<i64>,
790}
791
792#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
794pub enum ParagraphDropCapType {
795 #[serde(rename = "drop")]
796 Drop,
797 #[serde(rename = "margin")]
798 Margin,
799}
800
801#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
803#[serde(rename_all = "camelCase")]
804pub struct ParagraphDropCap {
805 #[serde(rename = "type")]
806 pub drop_cap_type: ParagraphDropCapType,
807 #[serde(skip_serializing_if = "Option::is_none")]
808 pub lines: Option<i64>,
809 #[serde(skip_serializing_if = "Option::is_none")]
810 pub wrap: Option<String>,
811 #[serde(skip_serializing_if = "Option::is_none")]
812 pub horizontal_anchor: Option<String>,
813 #[serde(skip_serializing_if = "Option::is_none")]
814 pub vertical_anchor: Option<String>,
815 #[serde(skip_serializing_if = "Option::is_none")]
816 pub x_twips: Option<i64>,
817 #[serde(skip_serializing_if = "Option::is_none")]
818 pub y_twips: Option<i64>,
819 #[serde(skip_serializing_if = "Option::is_none")]
820 pub horizontal_space_twips: Option<i64>,
821 #[serde(skip_serializing_if = "Option::is_none")]
822 pub vertical_space_twips: Option<i64>,
823}
824
825#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
826#[serde(rename_all = "camelCase")]
827pub enum ParagraphTextAlignment {
828 Auto,
829 Top,
830 Center,
831 Baseline,
832 Bottom,
833}
834
835#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
837#[serde(rename_all = "camelCase")]
838pub struct ParagraphStyle {
839 #[serde(skip_serializing_if = "Option::is_none")]
840 pub source_before_auto_spacing: Option<bool>,
841 #[serde(skip_serializing_if = "Option::is_none")]
842 pub source_after_auto_spacing: Option<bool>,
843 #[serde(skip_serializing_if = "Option::is_none")]
844 pub align: Option<ParagraphAlignment>,
845 #[serde(skip_serializing_if = "Option::is_none")]
846 pub snap_to_grid: Option<bool>,
847 #[serde(skip_serializing_if = "Option::is_none")]
848 pub source_snap_to_grid: Option<bool>,
849 #[serde(skip_serializing_if = "Option::is_none")]
850 pub source_has_snap_to_grid: Option<bool>,
851 #[serde(skip_serializing_if = "Option::is_none")]
852 pub source_inherited_snap_to_grid: Option<bool>,
853 #[serde(skip_serializing_if = "Option::is_none")]
854 pub source_table_snap_to_grid: Option<bool>,
855 #[serde(skip_serializing_if = "Option::is_none")]
856 pub text_alignment: Option<ParagraphTextAlignment>,
857 #[serde(skip_serializing_if = "Option::is_none")]
858 pub source_text_alignment: Option<ParagraphTextAlignment>,
859 #[serde(skip_serializing_if = "Option::is_none")]
860 pub source_has_text_alignment: Option<bool>,
861 #[serde(skip_serializing_if = "Option::is_none")]
862 pub source_inherited_text_alignment: Option<ParagraphTextAlignment>,
863 #[serde(skip_serializing_if = "Option::is_none")]
864 pub source_table_text_alignment: Option<ParagraphTextAlignment>,
865 #[serde(skip_serializing_if = "Option::is_none")]
866 pub heading_level: Option<HeadingLevel>,
867 #[serde(skip_serializing_if = "Option::is_none")]
868 pub style_id: Option<String>,
869 #[serde(skip_serializing_if = "Option::is_none")]
870 pub style_name: Option<String>,
871 #[serde(skip_serializing_if = "Option::is_none")]
872 pub numbering: Option<ParagraphNumbering>,
873 #[serde(skip_serializing_if = "Option::is_none")]
874 pub spacing: Option<ParagraphSpacing>,
875 #[serde(skip_serializing_if = "Option::is_none")]
876 pub indent: Option<ParagraphIndent>,
877 #[serde(skip_serializing_if = "Option::is_none")]
878 pub background_color: Option<String>,
879 #[serde(skip_serializing_if = "Option::is_none")]
880 pub borders: Option<ParagraphBorderSet>,
881 #[serde(skip_serializing_if = "Option::is_none")]
882 pub tab_stops: Option<Vec<ParagraphTabStop>>,
883 #[serde(skip_serializing_if = "Option::is_none")]
884 pub contextual_spacing: Option<bool>,
885 #[serde(skip_serializing_if = "Option::is_none")]
886 pub keep_next: Option<bool>,
887 #[serde(skip_serializing_if = "Option::is_none")]
888 pub keep_lines: Option<bool>,
889 #[serde(skip_serializing_if = "Option::is_none")]
890 pub widow_control: Option<bool>,
891 #[serde(skip_serializing_if = "Option::is_none")]
892 pub page_break_before: Option<bool>,
893 #[serde(skip_serializing_if = "Option::is_none")]
894 pub drop_cap: Option<ParagraphDropCap>,
895}
896
897#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
899#[serde(rename_all = "camelCase")]
900pub struct ParagraphSourceTextPatchRun {
901 #[serde(skip_serializing_if = "Option::is_none")]
902 pub style: Option<SharedTextStyle>,
903 #[serde(skip_serializing_if = "Option::is_none")]
904 pub link: Option<String>,
905 #[serde(skip_serializing_if = "Option::is_none")]
906 pub note_reference: Option<NoteReference>,
907}
908
909#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
910#[serde(rename_all = "camelCase")]
911pub struct ParagraphSourceTextPatch {
912 pub runs: Vec<ParagraphSourceTextPatchRun>,
913}
914
915#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
917#[serde(rename_all = "camelCase")]
918pub struct ParagraphMarkFormattingSource {
919 #[serde(skip_serializing_if = "Option::is_none")]
920 pub default_style: Option<SharedTextStyle>,
921 #[serde(skip_serializing_if = "Option::is_none")]
922 pub character_style: Option<SharedTextStyle>,
923 #[serde(skip_serializing_if = "Option::is_none")]
924 pub direct_style: Option<SharedTextStyle>,
925}
926
927#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
929#[serde(rename_all = "camelCase")]
930pub struct ParagraphNode {
931 #[serde(default, skip_serializing_if = "Option::is_none")]
932 pub block_id: Option<String>,
933 #[serde(default = "default_paragraph_node_type", rename = "type")]
934 pub r#type: ParagraphNodeType,
935 pub children: Vec<ParagraphChildNode>,
936 #[serde(skip_serializing_if = "Option::is_none")]
937 pub style: Option<SharedParagraphStyle>,
938 #[serde(skip_serializing_if = "Option::is_none")]
939 pub paragraph_mark_style: Option<SharedTextStyle>,
940 #[serde(skip_serializing_if = "Option::is_none")]
941 pub source_paragraph_mark_style: Option<SharedTextStyle>,
942 #[serde(skip_serializing_if = "Option::is_none")]
943 pub source_paragraph_mark_formatting: Option<ParagraphMarkFormattingSource>,
944 #[serde(skip_serializing_if = "Option::is_none")]
945 pub source_paragraph_mark_properties_xml: Option<String>,
946 #[serde(skip_serializing_if = "Option::is_none")]
947 pub paragraph_mark_deleted: Option<bool>,
948 #[serde(skip_serializing_if = "Option::is_none")]
949 pub source_xml: Option<String>,
950 #[serde(skip_serializing_if = "Option::is_none")]
951 pub source_text_patch: Option<ParagraphSourceTextPatch>,
952 #[serde(skip_serializing_if = "Option::is_none")]
955 pub source_run_provenance: Option<ParagraphSourceTextPatch>,
956}
957
958#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
960pub enum ParagraphNodeType {
961 #[serde(rename = "paragraph")]
962 Paragraph,
963}
964
965#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
967#[serde(rename_all = "camelCase")]
968pub struct TableBoxSpacing {
969 #[serde(skip_serializing_if = "Option::is_none")]
970 pub top_twips: Option<i64>,
971 #[serde(skip_serializing_if = "Option::is_none")]
972 pub right_twips: Option<i64>,
973 #[serde(skip_serializing_if = "Option::is_none")]
974 pub bottom_twips: Option<i64>,
975 #[serde(skip_serializing_if = "Option::is_none")]
976 pub left_twips: Option<i64>,
977}
978
979#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
981#[serde(rename_all = "camelCase")]
982pub struct TableBorderStyle {
983 #[serde(rename = "type")]
984 pub border_type: String,
985 #[serde(skip_serializing_if = "Option::is_none")]
986 pub color: Option<String>,
987 #[serde(skip_serializing_if = "Option::is_none")]
988 pub size_eighth_pt: Option<f64>,
989}
990
991#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
993#[serde(rename_all = "camelCase")]
994pub struct TableBorderSet {
995 #[serde(skip_serializing_if = "Option::is_none")]
996 pub top: Option<TableBorderStyle>,
997 #[serde(skip_serializing_if = "Option::is_none")]
998 pub right: Option<TableBorderStyle>,
999 #[serde(skip_serializing_if = "Option::is_none")]
1000 pub bottom: Option<TableBorderStyle>,
1001 #[serde(skip_serializing_if = "Option::is_none")]
1002 pub left: Option<TableBorderStyle>,
1003 #[serde(skip_serializing_if = "Option::is_none")]
1004 pub inside_h: Option<TableBorderStyle>,
1005 #[serde(skip_serializing_if = "Option::is_none")]
1006 pub inside_v: Option<TableBorderStyle>,
1007 #[serde(skip_serializing_if = "Option::is_none")]
1008 pub tl2br: Option<TableBorderStyle>,
1009 #[serde(skip_serializing_if = "Option::is_none")]
1010 pub tr2bl: Option<TableBorderStyle>,
1011}
1012
1013#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1015#[serde(rename_all = "camelCase")]
1016pub enum TableCellVerticalAlign {
1017 Top,
1018 Center,
1019 Bottom,
1020}
1021
1022#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1024#[serde(tag = "type", rename_all = "camelCase")]
1025pub enum TablePreferredWidth {
1026 Dxa { value: f64 },
1027 Pct { value: f64 },
1028 Auto,
1029 Nil,
1030}
1031
1032#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1034#[serde(rename_all = "camelCase")]
1035pub struct TableWidthSource {
1036 #[serde(skip_serializing_if = "Option::is_none")]
1037 pub preferred_width: Option<TablePreferredWidth>,
1038 #[serde(skip_serializing_if = "Option::is_none")]
1039 pub width_twips: Option<i64>,
1040 #[serde(skip_serializing_if = "Option::is_none")]
1041 pub inherited_preferred_width: Option<TablePreferredWidth>,
1042}
1043
1044#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1045#[serde(rename_all = "camelCase")]
1046pub enum TableAlignment {
1047 Left,
1048 Center,
1049 Right,
1050}
1051
1052#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1054#[serde(rename_all = "camelCase")]
1055pub struct TableCellStyle {
1056 #[serde(skip_serializing_if = "Option::is_none")]
1057 pub background_color: Option<String>,
1058 #[serde(skip_serializing_if = "Option::is_none")]
1059 pub grid_span: Option<i64>,
1060 #[serde(skip_serializing_if = "Option::is_none")]
1061 pub row_span: Option<i64>,
1062 #[serde(skip_serializing_if = "Option::is_none")]
1063 pub v_merge_continuation: Option<bool>,
1064 #[serde(skip_serializing_if = "Option::is_none")]
1065 pub width_twips: Option<i64>,
1066 #[serde(skip_serializing_if = "Option::is_none")]
1067 pub preferred_width: Option<TablePreferredWidth>,
1068 #[serde(skip_serializing_if = "Option::is_none")]
1069 pub source_width: Option<TableWidthSource>,
1070 #[serde(skip_serializing_if = "Option::is_none")]
1071 pub margin_twips: Option<TableBoxSpacing>,
1072 #[serde(skip_serializing_if = "Option::is_none")]
1073 pub vertical_align: Option<TableCellVerticalAlign>,
1074 #[serde(skip_serializing_if = "Option::is_none")]
1075 pub text_direction: Option<String>,
1076 #[serde(skip_serializing_if = "Option::is_none")]
1077 pub source_text_direction: Option<String>,
1078 #[serde(skip_serializing_if = "Option::is_none")]
1079 pub no_wrap: Option<bool>,
1080 #[serde(skip_serializing_if = "Option::is_none")]
1081 pub source_no_wrap: Option<bool>,
1082 #[serde(skip_serializing_if = "Option::is_none")]
1083 pub borders: Option<TableBorderSet>,
1084}
1085
1086#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1088#[serde(untagged)]
1089pub enum TableCellContentNode {
1090 Paragraph(ParagraphNode),
1091 Table(Box<TableNode>),
1092}
1093
1094#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1096#[serde(rename_all = "camelCase")]
1097pub struct TableCellNode {
1098 #[serde(default = "default_table_cell_node_type", rename = "type")]
1099 pub r#type: TableCellNodeType,
1100 pub nodes: Vec<TableCellContentNode>,
1101 #[serde(skip_serializing_if = "Option::is_none")]
1102 pub style: Option<TableCellStyle>,
1103}
1104
1105#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1107pub enum TableCellNodeType {
1108 #[serde(rename = "table-cell")]
1109 TableCell,
1110}
1111
1112#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1114pub enum TableRowHeightRule {
1115 #[serde(rename = "auto")]
1116 Auto,
1117 #[serde(rename = "atLeast")]
1118 AtLeast,
1119 #[serde(rename = "exact")]
1120 Exact,
1121}
1122
1123#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1125#[serde(rename_all = "camelCase")]
1126pub struct TableRowGeometrySource {
1127 #[serde(skip_serializing_if = "Option::is_none")]
1128 pub grid_before: Option<i64>,
1129 #[serde(skip_serializing_if = "Option::is_none")]
1130 pub grid_after: Option<i64>,
1131 #[serde(skip_serializing_if = "Option::is_none")]
1132 pub width_before: Option<TablePreferredWidth>,
1133 #[serde(skip_serializing_if = "Option::is_none")]
1134 pub width_after: Option<TablePreferredWidth>,
1135}
1136
1137#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1139#[serde(rename_all = "camelCase")]
1140pub struct TableRowStyle {
1141 #[serde(skip_serializing_if = "Option::is_none")]
1142 pub grid_before: Option<i64>,
1143 #[serde(skip_serializing_if = "Option::is_none")]
1144 pub grid_after: Option<i64>,
1145 #[serde(skip_serializing_if = "Option::is_none")]
1146 pub width_before: Option<TablePreferredWidth>,
1147 #[serde(skip_serializing_if = "Option::is_none")]
1148 pub width_after: Option<TablePreferredWidth>,
1149 #[serde(skip_serializing_if = "Option::is_none")]
1150 pub source_row_geometry: Option<TableRowGeometrySource>,
1151 #[serde(skip_serializing_if = "Option::is_none")]
1152 pub background_color: Option<String>,
1153 #[serde(skip_serializing_if = "Option::is_none")]
1154 pub height_twips: Option<i64>,
1155 #[serde(skip_serializing_if = "Option::is_none")]
1156 pub height_rule: Option<TableRowHeightRule>,
1157 #[serde(skip_serializing_if = "Option::is_none")]
1158 pub cant_split: Option<bool>,
1159 #[serde(skip_serializing_if = "Option::is_none")]
1160 pub is_header: Option<bool>,
1161}
1162
1163#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1165#[serde(rename_all = "camelCase")]
1166pub struct TableRowNode {
1167 #[serde(default = "default_table_row_node_type", rename = "type")]
1168 pub r#type: TableRowNodeType,
1169 pub cells: Vec<TableCellNode>,
1170 #[serde(skip_serializing_if = "Option::is_none")]
1171 pub style: Option<TableRowStyle>,
1172}
1173
1174#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1176pub enum TableRowNodeType {
1177 #[serde(rename = "table-row")]
1178 TableRow,
1179}
1180
1181#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1183pub enum TableLayout {
1184 #[serde(rename = "fixed")]
1185 Fixed,
1186 #[serde(rename = "autofit")]
1187 Autofit,
1188}
1189
1190#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1192#[serde(rename_all = "camelCase")]
1193pub struct TableFloating {
1194 #[serde(skip_serializing_if = "Option::is_none")]
1195 pub x_twips: Option<i64>,
1196 #[serde(skip_serializing_if = "Option::is_none")]
1197 pub y_twips: Option<i64>,
1198 #[serde(skip_serializing_if = "Option::is_none")]
1199 pub left_from_text_twips: Option<i64>,
1200 #[serde(skip_serializing_if = "Option::is_none")]
1201 pub right_from_text_twips: Option<i64>,
1202 #[serde(skip_serializing_if = "Option::is_none")]
1203 pub top_from_text_twips: Option<i64>,
1204 #[serde(skip_serializing_if = "Option::is_none")]
1205 pub bottom_from_text_twips: Option<i64>,
1206 #[serde(skip_serializing_if = "Option::is_none")]
1207 pub horizontal_anchor: Option<String>,
1208 #[serde(skip_serializing_if = "Option::is_none")]
1209 pub vertical_anchor: Option<String>,
1210 #[serde(skip_serializing_if = "Option::is_none")]
1211 pub horizontal_align: Option<ImageHorizontalAlign>,
1212 #[serde(skip_serializing_if = "Option::is_none")]
1213 pub vertical_align: Option<ImageVerticalAlign>,
1214}
1215
1216#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1218#[serde(rename_all = "camelCase")]
1219pub struct TableStyle {
1220 #[serde(skip_serializing_if = "Option::is_none")]
1221 pub style_id: Option<String>,
1222 #[serde(skip_serializing_if = "Option::is_none")]
1223 pub source_style_id: Option<String>,
1224 #[serde(skip_serializing_if = "Option::is_none")]
1225 pub width_twips: Option<i64>,
1226 #[serde(skip_serializing_if = "Option::is_none")]
1227 pub preferred_width: Option<TablePreferredWidth>,
1228 #[serde(skip_serializing_if = "Option::is_none")]
1229 pub source_width: Option<TableWidthSource>,
1230 #[serde(skip_serializing_if = "Option::is_none")]
1231 pub alignment: Option<TableAlignment>,
1232 #[serde(skip_serializing_if = "Option::is_none")]
1233 pub source_alignment: Option<TableAlignment>,
1234 #[serde(skip_serializing_if = "Option::is_none")]
1235 pub source_inherited_alignment: Option<TableAlignment>,
1236 #[serde(skip_serializing_if = "Option::is_none")]
1237 pub bidi_visual: Option<bool>,
1238 #[serde(skip_serializing_if = "Option::is_none")]
1239 pub source_bidi_visual: Option<bool>,
1240 #[serde(skip_serializing_if = "Option::is_none")]
1241 pub source_inherited_bidi_visual: Option<bool>,
1242 #[serde(skip_serializing_if = "Option::is_none")]
1243 pub indent_twips: Option<i64>,
1244 #[serde(skip_serializing_if = "Option::is_none")]
1245 pub layout: Option<TableLayout>,
1246 #[serde(skip_serializing_if = "Option::is_none")]
1247 pub cell_spacing_twips: Option<i64>,
1248 #[serde(skip_serializing_if = "Option::is_none")]
1249 pub cell_margin_twips: Option<TableBoxSpacing>,
1250 #[serde(skip_serializing_if = "Option::is_none")]
1251 pub column_widths_twips: Option<Vec<i64>>,
1252 #[serde(skip_serializing_if = "Option::is_none")]
1255 pub collapsed_grid_columns: Option<Vec<usize>>,
1256 #[serde(skip_serializing_if = "Option::is_none")]
1257 pub borders: Option<TableBorderSet>,
1258 #[serde(skip_serializing_if = "Option::is_none")]
1259 pub floating: Option<TableFloating>,
1260}
1261
1262#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1264#[serde(rename_all = "camelCase")]
1265pub struct TableSourceTextPatch {
1266 pub source_paragraph_xml: String,
1267 pub paragraph: ParagraphNode,
1268}
1269
1270#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1272#[serde(rename_all = "camelCase")]
1273pub struct TableNode {
1274 #[serde(default, skip_serializing_if = "Option::is_none")]
1275 pub block_id: Option<String>,
1276 #[serde(default = "default_table_node_type", rename = "type")]
1277 pub r#type: TableNodeType,
1278 pub rows: Vec<TableRowNode>,
1279 #[serde(skip_serializing_if = "Option::is_none")]
1280 pub style: Option<TableStyle>,
1281 #[serde(skip_serializing_if = "Option::is_none")]
1282 pub source_xml: Option<String>,
1283 #[serde(skip_serializing_if = "Option::is_none")]
1284 pub source_text_patches: Option<Vec<TableSourceTextPatch>>,
1285}
1286
1287#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1289pub enum TableNodeType {
1290 #[serde(rename = "table")]
1291 Table,
1292}
1293
1294#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1296#[serde(untagged)]
1297pub enum DocNode {
1298 Paragraph(ParagraphNode),
1299 Table(TableNode),
1300}
1301
1302#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1304#[serde(rename_all = "camelCase")]
1305pub struct HeaderSection {
1306 pub part_name: String,
1307 #[serde(skip_serializing_if = "Option::is_none")]
1308 pub reference_type: Option<String>,
1309 pub nodes: Vec<DocNode>,
1310}
1311
1312#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1314#[serde(rename_all = "camelCase")]
1315pub struct FooterSection {
1316 pub part_name: String,
1317 #[serde(skip_serializing_if = "Option::is_none")]
1318 pub reference_type: Option<String>,
1319 pub nodes: Vec<DocNode>,
1320}
1321
1322#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1324#[serde(rename_all = "camelCase")]
1325pub struct DocumentSection {
1326 pub start_node_index: i64,
1327 #[serde(skip_serializing_if = "Option::is_none")]
1328 pub section_properties_xml: Option<String>,
1329 pub header_sections: Vec<HeaderSection>,
1330 pub footer_sections: Vec<FooterSection>,
1331}
1332
1333#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1335#[serde(rename_all = "camelCase")]
1336pub struct ParagraphStyleDefinition {
1337 pub id: String,
1338 pub name: String,
1339 #[serde(skip_serializing_if = "Option::is_none")]
1340 pub based_on_id: Option<String>,
1341 #[serde(skip_serializing_if = "Option::is_none")]
1342 pub next_style_id: Option<String>,
1343 #[serde(skip_serializing_if = "Option::is_none")]
1344 pub align: Option<ParagraphAlignment>,
1345 #[serde(skip_serializing_if = "Option::is_none")]
1346 pub snap_to_grid: Option<bool>,
1347 #[serde(skip_serializing_if = "Option::is_none")]
1348 pub source_has_snap_to_grid: Option<bool>,
1349 #[serde(skip_serializing_if = "Option::is_none")]
1350 pub text_alignment: Option<ParagraphTextAlignment>,
1351 #[serde(skip_serializing_if = "Option::is_none")]
1352 pub source_has_text_alignment: Option<bool>,
1353 #[serde(skip_serializing_if = "Option::is_none")]
1354 pub heading_level: Option<HeadingLevel>,
1355 #[serde(skip_serializing_if = "Option::is_none")]
1356 pub numbering: Option<ParagraphNumbering>,
1357 #[serde(skip_serializing_if = "Option::is_none")]
1358 pub spacing: Option<ParagraphSpacing>,
1359 #[serde(skip_serializing_if = "Option::is_none")]
1360 pub indent: Option<ParagraphIndent>,
1361 #[serde(skip_serializing_if = "Option::is_none")]
1362 pub background_color: Option<String>,
1363 #[serde(skip_serializing_if = "Option::is_none")]
1364 pub borders: Option<ParagraphBorderSet>,
1365 #[serde(skip_serializing_if = "Option::is_none")]
1366 pub tab_stops: Option<Vec<ParagraphTabStop>>,
1367 #[serde(skip_serializing_if = "Option::is_none")]
1368 pub contextual_spacing: Option<bool>,
1369 #[serde(skip_serializing_if = "Option::is_none")]
1370 pub keep_next: Option<bool>,
1371 #[serde(skip_serializing_if = "Option::is_none")]
1372 pub keep_lines: Option<bool>,
1373 #[serde(skip_serializing_if = "Option::is_none")]
1374 pub widow_control: Option<bool>,
1375 #[serde(skip_serializing_if = "Option::is_none")]
1376 pub page_break_before: Option<bool>,
1377 #[serde(skip_serializing_if = "Option::is_none")]
1378 pub run_style: Option<TextStyle>,
1379 #[serde(skip_serializing_if = "Option::is_none")]
1380 pub ui_priority: Option<i64>,
1381 #[serde(skip_serializing_if = "Option::is_none")]
1382 pub is_default: Option<bool>,
1383 #[serde(skip_serializing_if = "Option::is_none")]
1384 pub is_primary: Option<bool>,
1385}
1386
1387#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
1389pub enum NumberingLevelSuffix {
1390 #[serde(rename = "tab")]
1391 Tab,
1392 #[serde(rename = "space")]
1393 Space,
1394 #[serde(rename = "nothing")]
1395 Nothing,
1396}
1397
1398#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1400#[serde(rename_all = "camelCase")]
1401pub struct NumberingLevelDefinition {
1402 pub ilvl: i64,
1403 #[serde(skip_serializing_if = "Option::is_none")]
1404 pub start: Option<i64>,
1405 #[serde(skip_serializing_if = "Option::is_none")]
1406 pub format: Option<String>,
1407 #[serde(skip_serializing_if = "Option::is_none")]
1408 pub text: Option<String>,
1409 #[serde(skip_serializing_if = "Option::is_none")]
1410 pub suffix: Option<NumberingLevelSuffix>,
1411 #[serde(skip_serializing_if = "Option::is_none")]
1415 pub lvl_restart: Option<i64>,
1416 #[serde(skip_serializing_if = "Option::is_none")]
1419 pub is_lgl: Option<bool>,
1420 #[serde(skip_serializing_if = "Option::is_none")]
1421 pub indent: Option<ParagraphIndent>,
1422 #[serde(skip_serializing_if = "Option::is_none")]
1423 pub run_style: Option<TextStyle>,
1424 #[serde(skip_serializing_if = "Option::is_none")]
1425 pub bullet_font_family: Option<String>,
1426 #[serde(skip_serializing_if = "Option::is_none")]
1427 pub bullet_color: Option<String>,
1428 #[serde(skip_serializing_if = "Option::is_none")]
1429 pub picture_bullet_id: Option<i64>,
1430 #[serde(skip_serializing_if = "Option::is_none")]
1431 pub picture_bullet: Option<NumberingPictureBulletDefinition>,
1432}
1433
1434#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1436#[serde(rename_all = "camelCase")]
1437pub struct NumberingAbstractDefinition {
1438 pub abstract_num_id: i64,
1439 pub levels: Vec<NumberingLevelDefinition>,
1440}
1441
1442#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1444#[serde(rename_all = "camelCase")]
1445pub struct NumberingInstanceDefinition {
1446 pub num_id: i64,
1447 pub abstract_num_id: i64,
1448 #[serde(skip_serializing_if = "Option::is_none")]
1449 pub level_start_overrides: Option<HashMap<String, i64>>,
1450 #[serde(skip_serializing_if = "Option::is_none")]
1451 pub level_overrides: Option<Vec<NumberingLevelDefinition>>,
1452}
1453
1454#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1456#[serde(rename_all = "camelCase")]
1457pub struct NumberingDefinitionSet {
1458 pub abstracts: Vec<NumberingAbstractDefinition>,
1459 pub instances: Vec<NumberingInstanceDefinition>,
1460}
1461
1462#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1464#[serde(rename_all = "camelCase")]
1465pub struct NumberingPictureBulletDefinition {
1466 pub num_pic_bullet_id: i64,
1467 #[serde(skip_serializing_if = "Option::is_none")]
1468 pub src: Option<String>,
1469 #[serde(skip_serializing_if = "Option::is_none")]
1470 pub width_px: Option<f64>,
1471 #[serde(skip_serializing_if = "Option::is_none")]
1472 pub height_px: Option<f64>,
1473 #[serde(skip_serializing_if = "Option::is_none")]
1474 pub part_name: Option<String>,
1475 #[serde(skip_serializing_if = "Option::is_none")]
1476 pub content_type: Option<String>,
1477}
1478
1479#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1481#[serde(rename_all = "camelCase")]
1482pub struct DocumentNoteDefinition {
1483 pub id: i64,
1484 pub text: String,
1485 #[serde(skip_serializing_if = "Option::is_none")]
1486 pub nodes: Option<Vec<DocNode>>,
1487}
1488
1489#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1491#[serde(rename_all = "camelCase")]
1492pub struct DocumentCommentDefinition {
1493 #[serde(default, skip_serializing_if = "Option::is_none")]
1494 pub nodes: Option<Vec<DocNode>>,
1495 pub id: i64,
1496 #[serde(skip_serializing_if = "Option::is_none")]
1497 pub author: Option<String>,
1498 #[serde(skip_serializing_if = "Option::is_none")]
1499 pub initials: Option<String>,
1500 #[serde(skip_serializing_if = "Option::is_none")]
1501 pub date: Option<String>,
1502 pub text: String,
1503 #[serde(skip_serializing_if = "Option::is_none")]
1504 pub parent_id: Option<i64>,
1505 #[serde(skip_serializing_if = "Option::is_none")]
1506 pub resolved: Option<bool>,
1507 #[serde(skip_serializing_if = "Option::is_none")]
1508 pub source_xml: Option<String>,
1509 #[serde(skip_serializing_if = "Option::is_none")]
1510 pub extended_paragraph_id: Option<String>,
1511 #[serde(skip_serializing_if = "Option::is_none")]
1512 pub source_resolved: Option<bool>,
1513 #[serde(skip_serializing_if = "Option::is_none")]
1514 pub resolution_dirty: Option<bool>,
1515 #[serde(skip_serializing_if = "Option::is_none")]
1516 pub is_new: Option<bool>,
1517}
1518
1519#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1521#[serde(rename_all = "camelCase")]
1522pub struct DocumentCompatibilitySettings {
1523 #[serde(skip_serializing_if = "Option::is_none")]
1524 pub adjust_line_height_in_table: Option<bool>,
1525 #[serde(skip_serializing_if = "Option::is_none")]
1526 pub no_leading: Option<bool>,
1527 #[serde(
1528 rename = "suppressTopSpacingWP",
1529 skip_serializing_if = "Option::is_none"
1530 )]
1531 pub suppress_top_spacing_wp: Option<bool>,
1532 #[serde(
1533 rename = "truncateFontHeightsLikeWP6",
1534 skip_serializing_if = "Option::is_none"
1535 )]
1536 pub truncate_font_heights_like_wp6: Option<bool>,
1537 #[serde(skip_serializing_if = "Option::is_none")]
1538 pub no_extra_line_spacing: Option<bool>,
1539 #[serde(rename = "spaceForUL", skip_serializing_if = "Option::is_none")]
1540 pub space_for_ul: Option<bool>,
1541 #[serde(skip_serializing_if = "Option::is_none")]
1542 pub suppress_bottom_spacing: Option<bool>,
1543 #[serde(skip_serializing_if = "Option::is_none")]
1544 pub compatibility_mode: Option<i64>,
1545 #[serde(
1546 rename = "enableOpenTypeFeatures",
1547 skip_serializing_if = "Option::is_none"
1548 )]
1549 pub enable_open_type_features: Option<bool>,
1550 #[serde(skip_serializing_if = "Option::is_none")]
1551 pub suppress_spacing_before_after_page_break: Option<bool>,
1552 #[serde(skip_serializing_if = "Option::is_none")]
1553 pub use_printer_metrics: Option<bool>,
1554 #[serde(skip_serializing_if = "Option::is_none")]
1555 pub use_fixed_html_paragraph_spacing: Option<bool>,
1556 #[serde(skip_serializing_if = "Option::is_none")]
1557 pub do_not_break_wrapped_tables: Option<bool>,
1558 #[serde(skip_serializing_if = "Option::is_none")]
1559 pub do_not_break_constrained_forced_table: Option<bool>,
1560 #[serde(skip_serializing_if = "Option::is_none")]
1561 pub even_and_odd_headers: Option<bool>,
1562}
1563
1564#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1566#[serde(rename_all = "camelCase")]
1567pub struct DocModelMetadata {
1568 #[serde(default, skip_serializing_if = "Option::is_none")]
1569 pub document_id: Option<String>,
1570 #[serde(default, skip_serializing_if = "Option::is_none")]
1571 pub source_part_names: Option<std::collections::BTreeMap<String, String>>,
1572 pub source_parts: i64,
1573 pub warnings: Vec<String>,
1574 #[serde(skip_serializing_if = "Option::is_none")]
1575 pub document_page_count: Option<i64>,
1576 #[serde(skip_serializing_if = "Option::is_none")]
1577 pub document_open_tag: Option<String>,
1578 #[serde(skip_serializing_if = "Option::is_none")]
1579 pub document_background_color: Option<String>,
1580 #[serde(skip_serializing_if = "Option::is_none")]
1581 pub section_properties_xml: Option<String>,
1582 #[serde(skip_serializing_if = "Option::is_none")]
1583 pub sections: Option<Vec<DocumentSection>>,
1584 pub header_sections: Vec<HeaderSection>,
1585 pub footer_sections: Vec<FooterSection>,
1586 pub paragraph_styles: Vec<ParagraphStyleDefinition>,
1587 #[serde(skip_serializing_if = "Option::is_none")]
1588 pub default_paragraph_style_id: Option<String>,
1589 #[serde(skip_serializing_if = "Option::is_none")]
1590 pub default_tab_stop_twips: Option<i64>,
1591 #[serde(skip_serializing_if = "Option::is_none")]
1592 pub document_settings_imported: Option<bool>,
1593 #[serde(skip_serializing_if = "Option::is_none")]
1594 pub line_spacing_compatibility_imported: Option<bool>,
1595 #[serde(skip_serializing_if = "Option::is_none")]
1596 pub numbering_definitions: Option<NumberingDefinitionSet>,
1597 #[serde(skip_serializing_if = "Option::is_none")]
1598 pub compatibility: Option<DocumentCompatibilitySettings>,
1599 #[serde(skip_serializing_if = "Option::is_none")]
1600 pub footnotes: Option<Vec<DocumentNoteDefinition>>,
1601 #[serde(skip_serializing_if = "Option::is_none")]
1602 pub endnotes: Option<Vec<DocumentNoteDefinition>>,
1603 #[serde(skip_serializing_if = "Option::is_none")]
1604 pub comments: Option<Vec<DocumentCommentDefinition>>,
1605}
1606
1607#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
1609#[serde(rename_all = "camelCase")]
1610pub struct DocModel {
1611 pub nodes: Vec<DocNode>,
1612 pub metadata: DocModelMetadata,
1613}
1614
1615#[cfg(test)]
1616mod deserialize_tests {
1617 use super::{DocModel, DocNode, HeadingLevel, ParagraphAlignment};
1618
1619 #[test]
1620 fn deserializes_minimal_js_doc_model() {
1621 let json = r#"{"nodes":[{"type":"paragraph","children":[{"type":"text","text":"Hi"}]}],"metadata":{"sourceParts":1,"warnings":[],"headerSections":[],"footerSections":[],"paragraphStyles":[]}}"#;
1622 let model: DocModel = serde_json::from_str(json).expect("should deserialize");
1623 assert_eq!(model.nodes.len(), 1);
1624 }
1625
1626 #[test]
1627 fn deserializes_heading_level_two() {
1628 let json = r#"{"type":"paragraph","style":{"headingLevel":2},"children":[{"type":"text","text":"Added"}]}"#;
1629 let node: DocNode = serde_json::from_str(json).expect("heading level 2");
1630 let DocNode::Paragraph(paragraph) = node else {
1631 panic!("expected paragraph");
1632 };
1633 assert_eq!(
1634 paragraph.style.and_then(|style| style.heading_level),
1635 Some(HeadingLevel::Two)
1636 );
1637 }
1638
1639 #[test]
1640 fn deserializes_align_center() {
1641 let json = r#"{"type":"paragraph","style":{"align":"center"},"children":[{"type":"text","text":"Added"}]}"#;
1642 let node: DocNode = serde_json::from_str(json).expect("align center");
1643 let DocNode::Paragraph(paragraph) = node else {
1644 panic!("expected paragraph");
1645 };
1646 assert_eq!(
1647 paragraph.style.and_then(|style| style.align),
1648 Some(ParagraphAlignment::Center)
1649 );
1650 }
1651}
1652
1653#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
1655#[serde(transparent)]
1656pub struct SharedParagraphStyle(std::sync::Arc<ParagraphStyle>);
1657
1658impl SharedParagraphStyle {
1659 pub fn into_owned(self) -> ParagraphStyle {
1660 std::sync::Arc::unwrap_or_clone(self.0)
1661 }
1662}
1663
1664impl From<ParagraphStyle> for SharedParagraphStyle {
1665 fn from(style: ParagraphStyle) -> Self {
1666 Self(std::sync::Arc::new(style))
1667 }
1668}
1669
1670impl std::ops::Deref for SharedParagraphStyle {
1671 type Target = ParagraphStyle;
1672
1673 fn deref(&self) -> &ParagraphStyle {
1674 &self.0
1675 }
1676}
1677
1678impl std::ops::DerefMut for SharedParagraphStyle {
1679 fn deref_mut(&mut self) -> &mut ParagraphStyle {
1680 std::sync::Arc::make_mut(&mut self.0)
1681 }
1682}