use std::collections::HashMap;
use serde::{Deserialize, Serialize};
fn default_text_run_type() -> TextRunNodeType {
TextRunNodeType::Text
}
fn default_image_run_type() -> ImageRunNodeType {
ImageRunNodeType::Image
}
fn default_form_field_run_type() -> FormFieldRunNodeType {
FormFieldRunNodeType::FormField
}
fn default_paragraph_node_type() -> ParagraphNodeType {
ParagraphNodeType::Paragraph
}
fn default_table_cell_node_type() -> TableCellNodeType {
TableCellNodeType::TableCell
}
fn default_table_row_node_type() -> TableRowNodeType {
TableRowNodeType::TableRow
}
fn default_table_node_type() -> TableNodeType {
TableNodeType::Table
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ParagraphAlignment {
Left,
Center,
Right,
Justify,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)]
#[serde(into = "i64")]
pub enum HeadingLevel {
One = 1,
Two = 2,
Three = 3,
Four = 4,
Five = 5,
Six = 6,
Seven = 7,
Eight = 8,
Nine = 9,
}
impl<'de> Deserialize<'de> for HeadingLevel {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let value = i64::deserialize(deserializer)?;
match value {
1 => Ok(HeadingLevel::One),
2 => Ok(HeadingLevel::Two),
3 => Ok(HeadingLevel::Three),
4 => Ok(HeadingLevel::Four),
5 => Ok(HeadingLevel::Five),
6 => Ok(HeadingLevel::Six),
7 => Ok(HeadingLevel::Seven),
8 => Ok(HeadingLevel::Eight),
9 => Ok(HeadingLevel::Nine),
_ => Err(serde::de::Error::custom(format!(
"invalid heading level {value}"
))),
}
}
}
impl From<HeadingLevel> for i64 {
fn from(value: HeadingLevel) -> Self {
value as i64
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TextRunBorderStyle {
#[serde(rename = "type")]
pub border_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size_eighth_pt: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub space_pt: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub frame: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub shadow: Option<bool>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum VerticalAlign {
#[serde(rename = "superscript")]
Superscript,
#[serde(rename = "subscript")]
Subscript,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum TextLigatures {
None,
Standard,
Contextual,
Historical,
Discretional,
StandardContextual,
StandardHistorical,
ContextualHistorical,
StandardDiscretional,
ContextualDiscretional,
HistoricalDiscretional,
StandardContextualHistorical,
StandardContextualDiscretional,
StandardHistoricalDiscretional,
ContextualHistoricalDiscretional,
All,
}
impl TextLigatures {
pub fn from_xml_value(value: &str) -> Option<Self> {
match value {
"none" => Some(Self::None),
"standard" => Some(Self::Standard),
"contextual" => Some(Self::Contextual),
"historical" => Some(Self::Historical),
"discretional" => Some(Self::Discretional),
"standardContextual" => Some(Self::StandardContextual),
"standardHistorical" => Some(Self::StandardHistorical),
"contextualHistorical" => Some(Self::ContextualHistorical),
"standardDiscretional" => Some(Self::StandardDiscretional),
"contextualDiscretional" => Some(Self::ContextualDiscretional),
"historicalDiscretional" => Some(Self::HistoricalDiscretional),
"standardContextualHistorical" => Some(Self::StandardContextualHistorical),
"standardContextualDiscretional" => Some(Self::StandardContextualDiscretional),
"standardHistoricalDiscretional" => Some(Self::StandardHistoricalDiscretional),
"contextualHistoricalDiscretional" => Some(Self::ContextualHistoricalDiscretional),
"all" => Some(Self::All),
_ => None,
}
}
pub fn xml_value(self) -> &'static str {
match self {
Self::None => "none",
Self::Standard => "standard",
Self::Contextual => "contextual",
Self::Historical => "historical",
Self::Discretional => "discretional",
Self::StandardContextual => "standardContextual",
Self::StandardHistorical => "standardHistorical",
Self::ContextualHistorical => "contextualHistorical",
Self::StandardDiscretional => "standardDiscretional",
Self::ContextualDiscretional => "contextualDiscretional",
Self::HistoricalDiscretional => "historicalDiscretional",
Self::StandardContextualHistorical => "standardContextualHistorical",
Self::StandardContextualDiscretional => "standardContextualDiscretional",
Self::StandardHistoricalDiscretional => "standardHistoricalDiscretional",
Self::ContextualHistoricalDiscretional => "contextualHistoricalDiscretional",
Self::All => "all",
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TextStyle {
#[serde(skip_serializing_if = "Option::is_none")]
pub bold: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub italic: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub underline: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub strike: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub all_caps: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub small_caps: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub highlight: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub background_color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub font_size_pt: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub font_size_cs_pt: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub font_family: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_font_family: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub font_family_ascii: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub font_family_h_ansi: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub font_family_east_asia: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub font_family_cs: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub font_theme_ascii: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub font_theme_h_ansi: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub font_theme_east_asia: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub font_theme_cs: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resolved_font_family_ascii: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resolved_font_family_h_ansi: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resolved_font_family_east_asia: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resolved_font_family_cs: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub font_hint: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language_east_asia: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub language_bidi: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub right_to_left: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub complex_script: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub character_spacing_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub character_scale_percent: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_character_scale: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub kerning_min_font_size_pt: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ligatures: Option<TextLigatures>,
#[serde(skip_serializing_if = "Option::is_none")]
pub contextual_alternates: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vertical_align: Option<VerticalAlign>,
#[serde(skip_serializing_if = "Option::is_none")]
pub run_border: Option<TextRunBorderStyle>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct SharedTextStyle(std::sync::Arc<TextStyle>);
impl SharedTextStyle {
pub fn into_owned(self) -> TextStyle {
std::sync::Arc::unwrap_or_clone(self.0)
}
}
impl From<TextStyle> for SharedTextStyle {
fn from(style: TextStyle) -> Self {
Self(std::sync::Arc::new(style))
}
}
impl std::ops::Deref for SharedTextStyle {
type Target = TextStyle;
fn deref(&self) -> &TextStyle {
&self.0
}
}
impl std::ops::DerefMut for SharedTextStyle {
fn deref_mut(&mut self) -> &mut TextStyle {
std::sync::Arc::make_mut(&mut self.0)
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NoteReference {
pub kind: NoteReferenceKind,
pub id: i64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum NoteReferenceKind {
#[serde(rename = "footnote")]
Footnote,
#[serde(rename = "endnote")]
Endnote,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TextRunNode {
#[serde(default = "default_text_run_type", rename = "type")]
pub r#type: TextRunNodeType,
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub style: Option<SharedTextStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub link: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub note_reference: Option<NoteReference>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum TextRunNodeType {
#[serde(rename = "text")]
Text,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ImageCrop {
#[serde(skip_serializing_if = "Option::is_none")]
pub left_fraction: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub top_fraction: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub right_fraction: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bottom_fraction: Option<f64>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ImageHorizontalAlign {
Left,
Center,
Right,
Inside,
Outside,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ImageVerticalAlign {
Top,
Center,
Bottom,
Inside,
Outside,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ImageWrapType {
#[serde(rename = "none")]
WrapNone,
#[serde(rename = "square")]
Square,
#[serde(rename = "tight")]
Tight,
#[serde(rename = "through")]
Through,
#[serde(rename = "topAndBottom")]
TopAndBottom,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ImageWrapText {
#[serde(rename = "bothSides")]
BothSides,
#[serde(rename = "left")]
Left,
#[serde(rename = "right")]
Right,
#[serde(rename = "largest")]
Largest,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ImageFloating {
#[serde(skip_serializing_if = "Option::is_none")]
pub x_px: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub y_px: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub horizontal_align: Option<ImageHorizontalAlign>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vertical_align: Option<ImageVerticalAlign>,
#[serde(skip_serializing_if = "Option::is_none")]
pub horizontal_relative_to: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vertical_relative_to: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dist_l_px: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dist_r_px: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dist_t_px: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dist_b_px: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub wrap_type: Option<ImageWrapType>,
#[serde(skip_serializing_if = "Option::is_none")]
pub wrap_text: Option<ImageWrapText>,
#[serde(skip_serializing_if = "Option::is_none")]
pub behind_document: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub z_index: Option<i64>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ImagePaintBounds {
pub x_px: f64,
pub y_px: f64,
pub width_px: f64,
pub height_px: f64,
pub layout_width_px: f64,
pub layout_height_px: f64,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ImageRunNode {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub paint_bounds: Option<Box<ImagePaintBounds>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub math_ml: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub content_nodes: Option<Vec<DocNode>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub semantic_kind: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub block_id: Option<String>,
#[serde(default = "default_image_run_type", rename = "type")]
pub r#type: ImageRunNodeType,
#[serde(skip_serializing_if = "Option::is_none")]
pub src: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub alt: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub width_px: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub height_px: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub part_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub content_type: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub data: Option<Vec<u8>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_xml: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub crop: Option<ImageCrop>,
#[serde(skip_serializing_if = "Option::is_none")]
pub css_filter: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub css_opacity: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub floating: Option<ImageFloating>,
#[serde(skip_serializing_if = "Option::is_none")]
pub synthetic_text_box: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text_box_text: Option<String>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ImageRunNodeType {
#[serde(rename = "image")]
Image,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum FormFieldType {
#[serde(rename = "checkbox")]
Checkbox,
#[serde(rename = "text")]
Text,
#[serde(rename = "date")]
Date,
#[serde(rename = "dropdown")]
Dropdown,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum FormFieldSourceKind {
#[serde(rename = "sdt")]
Sdt,
#[serde(rename = "legacy")]
Legacy,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FormFieldOption {
pub display_text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FormFieldTextWidgetSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub input_type: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_length: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text_format: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FormFieldCheckboxWidgetSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub default_checked: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size_mode: Option<FormFieldCheckboxSizeMode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size_pt: Option<f64>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum FormFieldCheckboxSizeMode {
#[serde(rename = "auto")]
Auto,
#[serde(rename = "exact")]
Exact,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FormFieldDropdownWidgetSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub default_value: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FormFieldWidgetSettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub enabled: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub calc_on_exit: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<FormFieldTextWidgetSettings>,
#[serde(skip_serializing_if = "Option::is_none")]
pub checkbox: Option<FormFieldCheckboxWidgetSettings>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dropdown: Option<FormFieldDropdownWidgetSettings>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FormFieldSourcePreview {
pub relationship_id: String,
pub shape_id: String,
pub checked: bool,
pub image: Box<ImageRunNode>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FormFieldRunNode {
#[serde(default = "default_form_field_run_type", rename = "type")]
pub r#type: FormFieldRunNodeType,
pub field_type: FormFieldType,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_kind: Option<FormFieldSourceKind>,
#[serde(skip_serializing_if = "Option::is_none")]
pub id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tag: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub placeholder: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub checked: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub options: Option<Vec<FormFieldOption>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub widget: Option<FormFieldWidgetSettings>,
#[serde(skip_serializing_if = "Option::is_none")]
pub checked_symbol: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub unchecked_symbol: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub style: Option<SharedTextStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub link: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_xml: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_preview: Option<Box<FormFieldSourcePreview>>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum FormFieldRunNodeType {
#[serde(rename = "form-field")]
FormField,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ParagraphChildNode {
Text(TextRunNode),
Image(Box<ImageRunNode>),
FormField(Box<FormFieldRunNode>),
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ParagraphNumbering {
pub num_id: i64,
pub ilvl: i64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ParagraphLineRule {
#[serde(rename = "auto")]
Auto,
#[serde(rename = "exact")]
Exact,
#[serde(rename = "atLeast")]
AtLeast,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ParagraphSpacing {
#[serde(skip_serializing_if = "Option::is_none")]
pub before_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub after_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub before_auto_spacing: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub after_auto_spacing: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub line_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub line_rule: Option<ParagraphLineRule>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ParagraphIndent {
#[serde(skip_serializing_if = "Option::is_none")]
pub left_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub right_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub first_line_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub hanging_twips: Option<i64>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ParagraphBorderStyle {
#[serde(rename = "type")]
pub border_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size_eighth_pt: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub space_pt: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub frame: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub shadow: Option<bool>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ParagraphBorderSet {
#[serde(skip_serializing_if = "Option::is_none")]
pub top: Option<ParagraphBorderStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub right: Option<ParagraphBorderStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bottom: Option<ParagraphBorderStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub left: Option<ParagraphBorderStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub between: Option<ParagraphBorderStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bar: Option<ParagraphBorderStyle>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ParagraphTabStopAlignment {
Clear,
Left,
Center,
Right,
Decimal,
Bar,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ParagraphTabStopLeader {
#[serde(rename = "none")]
LeaderNone,
#[serde(rename = "dot")]
Dot,
#[serde(rename = "hyphen")]
Hyphen,
#[serde(rename = "underscore")]
Underscore,
#[serde(rename = "middleDot")]
MiddleDot,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ParagraphTabStop {
#[serde(skip_serializing_if = "Option::is_none")]
pub alignment: Option<ParagraphTabStopAlignment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub leader: Option<ParagraphTabStopLeader>,
#[serde(skip_serializing_if = "Option::is_none")]
pub position_twips: Option<i64>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ParagraphDropCapType {
#[serde(rename = "drop")]
Drop,
#[serde(rename = "margin")]
Margin,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ParagraphDropCap {
#[serde(rename = "type")]
pub drop_cap_type: ParagraphDropCapType,
#[serde(skip_serializing_if = "Option::is_none")]
pub lines: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub wrap: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub horizontal_anchor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vertical_anchor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub x_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub y_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub horizontal_space_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vertical_space_twips: Option<i64>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum ParagraphTextAlignment {
Auto,
Top,
Center,
Baseline,
Bottom,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ParagraphStyle {
#[serde(skip_serializing_if = "Option::is_none")]
pub source_before_auto_spacing: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_after_auto_spacing: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub align: Option<ParagraphAlignment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub snap_to_grid: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_snap_to_grid: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_has_snap_to_grid: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_inherited_snap_to_grid: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_table_snap_to_grid: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text_alignment: Option<ParagraphTextAlignment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_text_alignment: Option<ParagraphTextAlignment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_has_text_alignment: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_inherited_text_alignment: Option<ParagraphTextAlignment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_table_text_alignment: Option<ParagraphTextAlignment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub heading_level: Option<HeadingLevel>,
#[serde(skip_serializing_if = "Option::is_none")]
pub style_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub style_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub numbering: Option<ParagraphNumbering>,
#[serde(skip_serializing_if = "Option::is_none")]
pub spacing: Option<ParagraphSpacing>,
#[serde(skip_serializing_if = "Option::is_none")]
pub indent: Option<ParagraphIndent>,
#[serde(skip_serializing_if = "Option::is_none")]
pub background_color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub borders: Option<ParagraphBorderSet>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tab_stops: Option<Vec<ParagraphTabStop>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub contextual_spacing: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keep_next: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keep_lines: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub widow_control: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_break_before: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub drop_cap: Option<ParagraphDropCap>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ParagraphSourceTextPatchRun {
#[serde(skip_serializing_if = "Option::is_none")]
pub style: Option<SharedTextStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub link: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub note_reference: Option<NoteReference>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ParagraphSourceTextPatch {
pub runs: Vec<ParagraphSourceTextPatchRun>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ParagraphMarkFormattingSource {
#[serde(skip_serializing_if = "Option::is_none")]
pub default_style: Option<SharedTextStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub character_style: Option<SharedTextStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub direct_style: Option<SharedTextStyle>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ParagraphNode {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub block_id: Option<String>,
#[serde(default = "default_paragraph_node_type", rename = "type")]
pub r#type: ParagraphNodeType,
pub children: Vec<ParagraphChildNode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub style: Option<SharedParagraphStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub paragraph_mark_style: Option<SharedTextStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_paragraph_mark_style: Option<SharedTextStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_paragraph_mark_formatting: Option<ParagraphMarkFormattingSource>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_paragraph_mark_properties_xml: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub paragraph_mark_deleted: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_xml: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_text_patch: Option<ParagraphSourceTextPatch>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_run_provenance: Option<ParagraphSourceTextPatch>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum ParagraphNodeType {
#[serde(rename = "paragraph")]
Paragraph,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TableBoxSpacing {
#[serde(skip_serializing_if = "Option::is_none")]
pub top_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub right_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bottom_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub left_twips: Option<i64>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TableBorderStyle {
#[serde(rename = "type")]
pub border_type: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size_eighth_pt: Option<f64>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TableBorderSet {
#[serde(skip_serializing_if = "Option::is_none")]
pub top: Option<TableBorderStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub right: Option<TableBorderStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bottom: Option<TableBorderStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub left: Option<TableBorderStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub inside_h: Option<TableBorderStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub inside_v: Option<TableBorderStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tl2br: Option<TableBorderStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tr2bl: Option<TableBorderStyle>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum TableCellVerticalAlign {
Top,
Center,
Bottom,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum TablePreferredWidth {
Dxa { value: f64 },
Pct { value: f64 },
Auto,
Nil,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TableWidthSource {
#[serde(skip_serializing_if = "Option::is_none")]
pub preferred_width: Option<TablePreferredWidth>,
#[serde(skip_serializing_if = "Option::is_none")]
pub width_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub inherited_preferred_width: Option<TablePreferredWidth>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub enum TableAlignment {
Left,
Center,
Right,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TableCellStyle {
#[serde(skip_serializing_if = "Option::is_none")]
pub background_color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub grid_span: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub row_span: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub v_merge_continuation: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub width_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub preferred_width: Option<TablePreferredWidth>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_width: Option<TableWidthSource>,
#[serde(skip_serializing_if = "Option::is_none")]
pub margin_twips: Option<TableBoxSpacing>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vertical_align: Option<TableCellVerticalAlign>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text_direction: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_text_direction: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub no_wrap: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_no_wrap: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub borders: Option<TableBorderSet>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum TableCellContentNode {
Paragraph(ParagraphNode),
Table(Box<TableNode>),
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TableCellNode {
#[serde(default = "default_table_cell_node_type", rename = "type")]
pub r#type: TableCellNodeType,
pub nodes: Vec<TableCellContentNode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub style: Option<TableCellStyle>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum TableCellNodeType {
#[serde(rename = "table-cell")]
TableCell,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum TableRowHeightRule {
#[serde(rename = "auto")]
Auto,
#[serde(rename = "atLeast")]
AtLeast,
#[serde(rename = "exact")]
Exact,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TableRowGeometrySource {
#[serde(skip_serializing_if = "Option::is_none")]
pub grid_before: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub grid_after: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub width_before: Option<TablePreferredWidth>,
#[serde(skip_serializing_if = "Option::is_none")]
pub width_after: Option<TablePreferredWidth>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TableRowStyle {
#[serde(skip_serializing_if = "Option::is_none")]
pub grid_before: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub grid_after: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub width_before: Option<TablePreferredWidth>,
#[serde(skip_serializing_if = "Option::is_none")]
pub width_after: Option<TablePreferredWidth>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_row_geometry: Option<TableRowGeometrySource>,
#[serde(skip_serializing_if = "Option::is_none")]
pub background_color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub height_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub height_rule: Option<TableRowHeightRule>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cant_split: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_header: Option<bool>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TableRowNode {
#[serde(default = "default_table_row_node_type", rename = "type")]
pub r#type: TableRowNodeType,
pub cells: Vec<TableCellNode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub style: Option<TableRowStyle>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum TableRowNodeType {
#[serde(rename = "table-row")]
TableRow,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum TableLayout {
#[serde(rename = "fixed")]
Fixed,
#[serde(rename = "autofit")]
Autofit,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TableFloating {
#[serde(skip_serializing_if = "Option::is_none")]
pub x_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub y_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub left_from_text_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub right_from_text_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub top_from_text_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bottom_from_text_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub horizontal_anchor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vertical_anchor: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub horizontal_align: Option<ImageHorizontalAlign>,
#[serde(skip_serializing_if = "Option::is_none")]
pub vertical_align: Option<ImageVerticalAlign>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TableStyle {
#[serde(skip_serializing_if = "Option::is_none")]
pub style_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_style_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub width_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub preferred_width: Option<TablePreferredWidth>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_width: Option<TableWidthSource>,
#[serde(skip_serializing_if = "Option::is_none")]
pub alignment: Option<TableAlignment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_alignment: Option<TableAlignment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_inherited_alignment: Option<TableAlignment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bidi_visual: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_bidi_visual: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_inherited_bidi_visual: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub indent_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub layout: Option<TableLayout>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cell_spacing_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cell_margin_twips: Option<TableBoxSpacing>,
#[serde(skip_serializing_if = "Option::is_none")]
pub column_widths_twips: Option<Vec<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub collapsed_grid_columns: Option<Vec<usize>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub borders: Option<TableBorderSet>,
#[serde(skip_serializing_if = "Option::is_none")]
pub floating: Option<TableFloating>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TableSourceTextPatch {
pub source_paragraph_xml: String,
pub paragraph: ParagraphNode,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct TableNode {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub block_id: Option<String>,
#[serde(default = "default_table_node_type", rename = "type")]
pub r#type: TableNodeType,
pub rows: Vec<TableRowNode>,
#[serde(skip_serializing_if = "Option::is_none")]
pub style: Option<TableStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_xml: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_text_patches: Option<Vec<TableSourceTextPatch>>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum TableNodeType {
#[serde(rename = "table")]
Table,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum DocNode {
Paragraph(ParagraphNode),
Table(TableNode),
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct HeaderSection {
pub part_name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub reference_type: Option<String>,
pub nodes: Vec<DocNode>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FooterSection {
pub part_name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub reference_type: Option<String>,
pub nodes: Vec<DocNode>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DocumentSection {
pub start_node_index: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub section_properties_xml: Option<String>,
pub header_sections: Vec<HeaderSection>,
pub footer_sections: Vec<FooterSection>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct ParagraphStyleDefinition {
pub id: String,
pub name: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub based_on_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub next_style_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub align: Option<ParagraphAlignment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub snap_to_grid: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_has_snap_to_grid: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text_alignment: Option<ParagraphTextAlignment>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_has_text_alignment: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub heading_level: Option<HeadingLevel>,
#[serde(skip_serializing_if = "Option::is_none")]
pub numbering: Option<ParagraphNumbering>,
#[serde(skip_serializing_if = "Option::is_none")]
pub spacing: Option<ParagraphSpacing>,
#[serde(skip_serializing_if = "Option::is_none")]
pub indent: Option<ParagraphIndent>,
#[serde(skip_serializing_if = "Option::is_none")]
pub background_color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub borders: Option<ParagraphBorderSet>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tab_stops: Option<Vec<ParagraphTabStop>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub contextual_spacing: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keep_next: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub keep_lines: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub widow_control: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub page_break_before: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub run_style: Option<TextStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub ui_priority: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_default: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_primary: Option<bool>,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum NumberingLevelSuffix {
#[serde(rename = "tab")]
Tab,
#[serde(rename = "space")]
Space,
#[serde(rename = "nothing")]
Nothing,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NumberingLevelDefinition {
pub ilvl: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub start: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub format: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub text: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub suffix: Option<NumberingLevelSuffix>,
#[serde(skip_serializing_if = "Option::is_none")]
pub lvl_restart: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_lgl: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub indent: Option<ParagraphIndent>,
#[serde(skip_serializing_if = "Option::is_none")]
pub run_style: Option<TextStyle>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bullet_font_family: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bullet_color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub picture_bullet_id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub picture_bullet: Option<NumberingPictureBulletDefinition>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NumberingAbstractDefinition {
pub abstract_num_id: i64,
pub levels: Vec<NumberingLevelDefinition>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NumberingInstanceDefinition {
pub num_id: i64,
pub abstract_num_id: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub level_start_overrides: Option<HashMap<String, i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub level_overrides: Option<Vec<NumberingLevelDefinition>>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NumberingDefinitionSet {
pub abstracts: Vec<NumberingAbstractDefinition>,
pub instances: Vec<NumberingInstanceDefinition>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct NumberingPictureBulletDefinition {
pub num_pic_bullet_id: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub src: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub width_px: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub height_px: Option<f64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub part_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub content_type: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DocumentNoteDefinition {
pub id: i64,
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub nodes: Option<Vec<DocNode>>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DocumentCommentDefinition {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub nodes: Option<Vec<DocNode>>,
pub id: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub author: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub initials: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub date: Option<String>,
pub text: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub parent_id: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resolved: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_xml: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub extended_paragraph_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub source_resolved: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub resolution_dirty: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_new: Option<bool>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DocumentCompatibilitySettings {
#[serde(skip_serializing_if = "Option::is_none")]
pub adjust_line_height_in_table: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub no_leading: Option<bool>,
#[serde(
rename = "suppressTopSpacingWP",
skip_serializing_if = "Option::is_none"
)]
pub suppress_top_spacing_wp: Option<bool>,
#[serde(
rename = "truncateFontHeightsLikeWP6",
skip_serializing_if = "Option::is_none"
)]
pub truncate_font_heights_like_wp6: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub no_extra_line_spacing: Option<bool>,
#[serde(rename = "spaceForUL", skip_serializing_if = "Option::is_none")]
pub space_for_ul: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub suppress_bottom_spacing: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub compatibility_mode: Option<i64>,
#[serde(
rename = "enableOpenTypeFeatures",
skip_serializing_if = "Option::is_none"
)]
pub enable_open_type_features: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub suppress_spacing_before_after_page_break: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub use_printer_metrics: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub use_fixed_html_paragraph_spacing: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub do_not_break_wrapped_tables: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub do_not_break_constrained_forced_table: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub even_and_odd_headers: Option<bool>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DocModelMetadata {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub document_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub source_part_names: Option<std::collections::BTreeMap<String, String>>,
pub source_parts: i64,
pub warnings: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub document_page_count: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub document_open_tag: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub document_background_color: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub section_properties_xml: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sections: Option<Vec<DocumentSection>>,
pub header_sections: Vec<HeaderSection>,
pub footer_sections: Vec<FooterSection>,
pub paragraph_styles: Vec<ParagraphStyleDefinition>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_paragraph_style_id: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub default_tab_stop_twips: Option<i64>,
#[serde(skip_serializing_if = "Option::is_none")]
pub document_settings_imported: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub line_spacing_compatibility_imported: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub numbering_definitions: Option<NumberingDefinitionSet>,
#[serde(skip_serializing_if = "Option::is_none")]
pub compatibility: Option<DocumentCompatibilitySettings>,
#[serde(skip_serializing_if = "Option::is_none")]
pub footnotes: Option<Vec<DocumentNoteDefinition>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub endnotes: Option<Vec<DocumentNoteDefinition>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub comments: Option<Vec<DocumentCommentDefinition>>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct DocModel {
pub nodes: Vec<DocNode>,
pub metadata: DocModelMetadata,
}
#[cfg(test)]
mod deserialize_tests {
use super::{DocModel, DocNode, HeadingLevel, ParagraphAlignment};
#[test]
fn deserializes_minimal_js_doc_model() {
let json = r#"{"nodes":[{"type":"paragraph","children":[{"type":"text","text":"Hi"}]}],"metadata":{"sourceParts":1,"warnings":[],"headerSections":[],"footerSections":[],"paragraphStyles":[]}}"#;
let model: DocModel = serde_json::from_str(json).expect("should deserialize");
assert_eq!(model.nodes.len(), 1);
}
#[test]
fn deserializes_heading_level_two() {
let json = r#"{"type":"paragraph","style":{"headingLevel":2},"children":[{"type":"text","text":"Added"}]}"#;
let node: DocNode = serde_json::from_str(json).expect("heading level 2");
let DocNode::Paragraph(paragraph) = node else {
panic!("expected paragraph");
};
assert_eq!(
paragraph.style.and_then(|style| style.heading_level),
Some(HeadingLevel::Two)
);
}
#[test]
fn deserializes_align_center() {
let json = r#"{"type":"paragraph","style":{"align":"center"},"children":[{"type":"text","text":"Added"}]}"#;
let node: DocNode = serde_json::from_str(json).expect("align center");
let DocNode::Paragraph(paragraph) = node else {
panic!("expected paragraph");
};
assert_eq!(
paragraph.style.and_then(|style| style.align),
Some(ParagraphAlignment::Center)
);
}
}
#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct SharedParagraphStyle(std::sync::Arc<ParagraphStyle>);
impl SharedParagraphStyle {
pub fn into_owned(self) -> ParagraphStyle {
std::sync::Arc::unwrap_or_clone(self.0)
}
}
impl From<ParagraphStyle> for SharedParagraphStyle {
fn from(style: ParagraphStyle) -> Self {
Self(std::sync::Arc::new(style))
}
}
impl std::ops::Deref for SharedParagraphStyle {
type Target = ParagraphStyle;
fn deref(&self) -> &ParagraphStyle {
&self.0
}
}
impl std::ops::DerefMut for SharedParagraphStyle {
fn deref_mut(&mut self) -> &mut ParagraphStyle {
std::sync::Arc::make_mut(&mut self.0)
}
}