use crate::format::DocumentFormat;
fn default_true() -> bool {
true
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum UnderlineStyle {
Single,
Double,
Thick,
Dotted,
Dash,
DotDash,
DotDotDash,
Wave,
Words,
None,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ParagraphAlignment {
Left,
Center,
Right,
Justify,
Distribute,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum LineSpacing {
Auto(u32),
Multiple(u32),
Exact(u32),
AtLeast(u32),
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum BorderStyle {
None,
Single,
Thick,
Double,
Dotted,
Dashed,
Wave,
DashSmallGap,
Outset,
Inset,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum CellVerticalAlign {
Top,
Center,
Bottom,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TableAlignment {
Left,
Center,
Right,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TextDirection {
LrTb,
TbRl,
BtLr,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ImageFormat {
Png,
Jpeg,
Gif,
Tiff,
Bmp,
Emf,
Wmf,
}
impl ImageFormat {
pub fn content_type(&self) -> &'static str {
match self {
Self::Png => "image/png",
Self::Jpeg => "image/jpeg",
Self::Gif => "image/gif",
Self::Tiff => "image/tiff",
Self::Bmp => "image/bmp",
Self::Emf => "image/x-emf",
Self::Wmf => "image/x-wmf",
}
}
pub fn extension(&self) -> &'static str {
match self {
Self::Png => "png",
Self::Jpeg => "jpg",
Self::Gif => "gif",
Self::Tiff => "tiff",
Self::Bmp => "bmp",
Self::Emf => "emf",
Self::Wmf => "wmf",
}
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ImagePositioning {
#[default]
Inline,
Floating(FloatingImage),
}
#[allow(dead_code)]
#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum SectionBreakType {
#[default]
Continuous,
NextPage,
EvenPage,
OddPage,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum VerticalAlign {
Superscript,
Subscript,
Baseline,
}
#[allow(dead_code)]
#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum FloatAnchor {
#[default]
Page,
Margin,
Column,
Paragraph,
}
#[allow(dead_code)]
#[derive(Debug, Clone, Default, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum TextWrap {
#[default]
Square,
Tight,
Through,
TopAndBottom,
Behind,
InFront,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ListStyle {
Bullet,
Decimal,
LowerRoman,
UpperRoman,
LowerAlpha,
UpperAlpha,
Dash,
Square,
Circle,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct BorderLine {
pub style: BorderStyle,
pub color: Option<[u8; 3]>,
pub size: Option<u32>,
pub space: Option<u32>,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct TableBorder {
pub top: Option<BorderLine>,
pub bottom: Option<BorderLine>,
pub left: Option<BorderLine>,
pub right: Option<BorderLine>,
pub inside_h: Option<BorderLine>,
pub inside_v: Option<BorderLine>,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct PageSetup {
pub width_twips: u32,
pub height_twips: u32,
pub margin_top_twips: u32,
pub margin_bottom_twips: u32,
pub margin_left_twips: u32,
pub margin_right_twips: u32,
pub landscape: bool,
pub header_distance_twips: u32,
pub footer_distance_twips: u32,
}
impl Default for PageSetup {
fn default() -> Self {
Self {
width_twips: 12240,
height_twips: 15840,
margin_top_twips: 1440,
margin_bottom_twips: 1440,
margin_left_twips: 1800,
margin_right_twips: 1800,
landscape: false,
header_distance_twips: 720,
footer_distance_twips: 720,
}
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct ColumnLayout {
pub count: u32,
pub space_twips: Option<u32>,
pub separator: bool,
#[serde(default)]
pub column_widths_twips: Vec<u32>,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ParagraphBorder {
pub top: Option<BorderLine>,
pub bottom: Option<BorderLine>,
pub left: Option<BorderLine>,
pub right: Option<BorderLine>,
pub between: Option<BorderLine>,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct CellPadding {
pub top_twips: Option<u32>,
pub bottom_twips: Option<u32>,
pub left_twips: Option<u32>,
pub right_twips: Option<u32>,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct FloatingImage {
pub x_emu: i64,
pub y_emu: i64,
pub width_emu: u64,
pub height_emu: u64,
pub h_anchor: FloatAnchor,
pub v_anchor: FloatAnchor,
pub text_wrap: TextWrap,
#[serde(default)]
pub allow_overlap: bool,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct HeaderFooter {
pub content: Vec<Element>,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct TextBox {
pub content: Vec<Element>,
pub width_emu: Option<u64>,
pub height_emu: Option<u64>,
pub x_emu: Option<i64>,
pub y_emu: Option<i64>,
#[serde(default)]
pub h_anchor: FloatAnchor,
#[serde(default)]
pub v_anchor: FloatAnchor,
#[serde(default)]
pub wrap: TextWrap,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct Note {
pub id: u32,
pub content: Vec<Element>,
pub marker: Option<String>,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct FootnoteRef {
pub note_id: u32,
pub marker: Option<String>,
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct CodeBlock {
pub language: Option<String>,
pub content: String,
}
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct DocumentIR {
pub metadata: Metadata,
pub sections: Vec<Section>,
}
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct Metadata {
pub format: DocumentFormat,
pub title: Option<String>,
pub author: Option<String>,
pub subject: Option<String>,
#[serde(default)]
pub keywords: Vec<String>,
pub created: Option<String>,
pub modified: Option<String>,
pub description: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct Section {
pub title: Option<String>,
pub elements: Vec<Element>,
pub page_setup: Option<PageSetup>,
pub columns: Option<ColumnLayout>,
#[serde(default)]
pub break_type: SectionBreakType,
pub header: Option<HeaderFooter>,
pub footer: Option<HeaderFooter>,
pub first_page_header: Option<HeaderFooter>,
pub first_page_footer: Option<HeaderFooter>,
pub even_page_header: Option<HeaderFooter>,
pub even_page_footer: Option<HeaderFooter>,
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
#[non_exhaustive]
pub enum Element {
Heading(Heading),
Paragraph(Paragraph),
Table(Table),
List(List),
Image(Image),
ThematicBreak,
TextBox(TextBox),
PageBreak,
ColumnBreak,
Footnote(Note),
Endnote(Note),
CodeBlock(CodeBlock),
}
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct Heading {
pub level: u8,
pub content: Vec<InlineContent>,
}
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct Paragraph {
pub content: Vec<InlineContent>,
pub alignment: Option<ParagraphAlignment>,
pub indent_left_twips: Option<i32>,
pub indent_right_twips: Option<i32>,
pub first_line_indent_twips: Option<i32>,
pub space_before_twips: Option<u32>,
pub space_after_twips: Option<u32>,
pub line_spacing: Option<LineSpacing>,
pub background_color: Option<[u8; 3]>,
pub border: Option<ParagraphBorder>,
#[serde(default)]
pub keep_with_next: bool,
#[serde(default)]
pub keep_together: bool,
#[serde(default)]
pub page_break_before: bool,
pub outline_level: Option<u8>,
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
#[non_exhaustive]
pub enum InlineContent {
Text(TextSpan),
LineBreak,
FootnoteRef(FootnoteRef),
EndnoteRef(FootnoteRef),
}
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct TextSpan {
pub text: String,
pub bold: bool,
pub italic: bool,
pub strikethrough: bool,
pub hyperlink: Option<String>,
pub font_size_half_pt: Option<u32>,
pub color: Option<[u8; 3]>,
pub underline: Option<UnderlineStyle>,
pub font_name: Option<String>,
pub highlight: Option<[u8; 3]>,
pub vertical_align: Option<VerticalAlign>,
#[serde(default)]
pub all_caps: bool,
#[serde(default)]
pub small_caps: bool,
pub char_spacing_half_pt: Option<i32>,
}
impl TextSpan {
pub fn plain(text: impl Into<String>) -> Self {
Self {
text: text.into(),
..Default::default()
}
}
}
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct Table {
pub rows: Vec<TableRow>,
#[serde(default)]
pub column_widths_twips: Vec<u32>,
pub border: Option<TableBorder>,
pub alignment: Option<TableAlignment>,
pub cell_padding_twips: Option<u32>,
pub caption: Option<String>,
pub width_twips: Option<u32>,
pub indent_left_twips: Option<i32>,
}
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct TableRow {
pub cells: Vec<TableCell>,
pub is_header: bool,
pub height_twips: Option<u32>,
#[serde(default = "default_true")]
pub allow_break: bool,
#[serde(default)]
pub repeat_as_header: bool,
}
impl Default for TableRow {
fn default() -> Self {
Self {
cells: Vec::new(),
is_header: false,
height_twips: None,
allow_break: true,
repeat_as_header: false,
}
}
}
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct TableCell {
pub content: Vec<Element>,
pub col_span: u32,
pub row_span: u32,
pub background_color: Option<[u8; 3]>,
pub border: Option<TableBorder>,
pub vertical_align: Option<CellVerticalAlign>,
pub text_align: Option<ParagraphAlignment>,
pub width_twips: Option<u32>,
pub padding: Option<CellPadding>,
pub text_direction: Option<TextDirection>,
}
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct List {
pub ordered: bool,
pub items: Vec<ListItem>,
pub start_number: Option<u32>,
pub style: Option<ListStyle>,
#[serde(default)]
pub level: u8,
}
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct ListItem {
pub content: Vec<Element>,
pub nested: Option<List>,
}
#[derive(Debug, Clone, PartialEq, Default, serde::Serialize, serde::Deserialize)]
pub struct Image {
pub alt_text: Option<String>,
pub data: Option<Vec<u8>>,
pub format: Option<ImageFormat>,
pub display_width_emu: Option<u64>,
pub display_height_emu: Option<u64>,
pub pixel_width: Option<u32>,
pub pixel_height: Option<u32>,
#[serde(default)]
pub decorative: bool,
#[serde(default)]
pub positioning: ImagePositioning,
}