pandoc_types/
definition.rs

1//! This module contatins the types from [Text.Pandoc.Definition] ported to Rust.
2//!
3//! [Text.Pandoc.Definition]: https://hackage.haskell.org/package/pandoc-types/docs/Text-Pandoc-Definition.html
4use std::collections::HashMap;
5
6pub use iter::*;
7use serde::ser::SerializeStruct;
8use serde::{Deserialize, Deserializer, Serialize, Serializer};
9use serde_tuple::{Deserialize_tuple, Serialize_tuple};
10
11pub mod extra;
12mod iter;
13
14const PANDOC_API_VERSION: [i32; 2] = [1, 23];
15
16#[derive(Debug, Clone, PartialEq, Default)]
17pub struct Pandoc {
18    pub blocks: Vec<Block>,
19    pub meta: HashMap<String, MetaValue>,
20}
21
22impl Serialize for Pandoc {
23    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
24    where
25        S: Serializer,
26    {
27        let mut value = serializer.serialize_struct("Pandoc", 3)?;
28        value.serialize_field("pandoc-api-version", &PANDOC_API_VERSION)?;
29        value.serialize_field("meta", &self.meta)?;
30        value.serialize_field("blocks", &self.blocks)?;
31        value.end()
32    }
33}
34
35impl<'a> Deserialize<'a> for Pandoc {
36    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
37    where
38        D: Deserializer<'a>,
39    {
40        #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
41        #[serde(rename = "Pandoc")]
42        struct Inner {
43            meta: HashMap<String, MetaValue>,
44            blocks: Vec<Block>,
45            #[serde(rename = "pandoc-api-version")]
46            version: Vec<i32>,
47        }
48
49        let value = Inner::deserialize(deserializer)?;
50
51        if value.version.len() < 2
52            || value.version[0] != PANDOC_API_VERSION[0]
53            || value.version[1] != PANDOC_API_VERSION[1]
54        {
55            return Err(serde::de::Error::custom(format!(
56                "expected pandoc-api-version to start with {},{}",
57                PANDOC_API_VERSION[0], PANDOC_API_VERSION[1]
58            )));
59        }
60
61        Ok(Pandoc {
62            meta: value.meta,
63            blocks: value.blocks,
64        })
65    }
66}
67
68#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
69#[serde(tag = "t", content = "c")]
70pub enum MetaValue {
71    MetaMap(HashMap<String, MetaValue>),
72    MetaList(Vec<MetaValue>),
73    MetaBool(bool),
74    MetaString(String),
75    MetaInlines(Vec<Inline>),
76    MetaBlocks(Vec<Block>),
77}
78
79#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
80#[serde(tag = "t", content = "c")]
81pub enum Block {
82    /// Plain text, not a paragraph
83    Plain(Vec<Inline>),
84    /// Paragraph
85    Para(Vec<Inline>),
86    /// Multiple non-breaking lines
87    LineBlock(Vec<Vec<Inline>>),
88    /// Code block (literal) with attributes
89    CodeBlock(Attr, String),
90    /// Raw block
91    RawBlock(Format, String),
92    /// Block quote
93    BlockQuote(Vec<Block>),
94    /// Ordered list (attributes and a list of items, each a list of blocks)
95    OrderedList(ListAttributes, Vec<Vec<Block>>),
96    /// Bullet list (list of items, each a list of blocks)
97    BulletList(Vec<Vec<Block>>),
98    /// Definition list. Each list item is a pair consisting of a term (a list of inlines) and one or more definitions (each a list of blocks)
99    DefinitionList(Vec<(Vec<Inline>, Vec<Vec<Block>>)>),
100    /// Header - level (integer) and text (inlines)
101    Header(i32, Attr, Vec<Inline>),
102    /// Horizontal rule
103    HorizontalRule,
104    /// Table
105    Table(Table),
106    /// Figure
107    Figure(Attr, Caption, Vec<Block>),
108    /// Generic block container with attributes
109    Div(Attr, Vec<Block>),
110    /// Nothing
111    Null,
112}
113
114#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq, Default)]
115pub struct Table {
116    pub attr: Attr,
117    pub caption: Caption,
118    pub colspecs: Vec<ColSpec>,
119    pub head: TableHead,
120    pub bodies: Vec<TableBody>,
121    pub foot: TableFoot,
122}
123
124#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
125#[serde(tag = "t", content = "c")]
126pub enum Inline {
127    /// Text
128    Str(String),
129    /// Emphasized text
130    Emph(Vec<Inline>),
131    /// Underlined text
132    Underline(Vec<Inline>),
133    /// Strongly emphasized text
134    Strong(Vec<Inline>),
135    /// Strikeout text
136    Strikeout(Vec<Inline>),
137    /// Superscripted text
138    Superscript(Vec<Inline>),
139    /// Subscripted text
140    Subscript(Vec<Inline>),
141    /// Small caps text
142    SmallCaps(Vec<Inline>),
143    /// Quoted text
144    Quoted(QuoteType, Vec<Inline>),
145    /// Citation
146    Cite(Vec<Citation>, Vec<Inline>),
147    /// Inline code
148    Code(Attr, String),
149    /// Inter-word space
150    Space,
151    /// Soft line break
152    SoftBreak,
153    /// Hard line break
154    LineBreak,
155    /// TeX math
156    Math(MathType, String),
157    /// Raw inline
158    RawInline(Format, String),
159    /// Hyperlink: alt text (list of inlines), target
160    Link(Attr, Vec<Inline>, Target),
161    /// Image: alt text (list of inlines), target
162    Image(Attr, Vec<Inline>, Target),
163    /// Footnote or endnote
164    Note(Vec<Block>),
165    /// Generic inline container with attributes
166    Span(Attr, Vec<Inline>),
167}
168
169#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
170#[serde(tag = "t", content = "c")]
171pub enum Alignment {
172    AlignLeft,
173    AlignRight,
174    AlignCenter,
175    AlignDefault,
176}
177
178impl Default for Alignment {
179    fn default() -> Self {
180        Self::AlignDefault
181    }
182}
183
184#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
185#[serde(tag = "t", content = "c")]
186pub enum ColWidth {
187    ColWidth(f64),
188    ColWidthDefault,
189}
190
191impl Default for ColWidth {
192    fn default() -> Self {
193        Self::ColWidthDefault
194    }
195}
196
197#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
198pub struct ColSpec(pub Alignment, pub ColWidth);
199
200#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq)]
201pub struct Row {
202    pub attr: Attr,
203    pub cells: Vec<Cell>,
204}
205
206#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq, Default)]
207pub struct TableHead {
208    pub attr: Attr,
209    pub rows: Vec<Row>,
210}
211
212#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq, Default)]
213pub struct TableBody {
214    pub attr: Attr,
215    pub row_head_columns: i32,
216    pub head: Vec<Row>,
217    pub body: Vec<Row>,
218}
219
220#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq, Default)]
221pub struct TableFoot {
222    pub attr: Attr,
223    pub rows: Vec<Row>,
224}
225
226#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq, Default)]
227pub struct Caption {
228    pub short: Option<Vec<Inline>>,
229    pub long: Vec<Block>,
230}
231
232#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq)]
233pub struct Cell {
234    pub attr: Attr,
235    pub align: Alignment,
236    pub row_span: i32,
237    pub col_span: i32,
238    pub content: Vec<Block>,
239}
240
241impl Default for Cell {
242    fn default() -> Self {
243        Self {
244            attr: Default::default(),
245            align: Default::default(),
246            row_span: 1,
247            col_span: 1,
248            content: Default::default(),
249        }
250    }
251}
252
253#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq)]
254pub struct ListAttributes {
255    pub start_number: i32,
256    pub style: ListNumberStyle,
257    pub delim: ListNumberDelim,
258}
259
260impl Default for ListAttributes {
261    fn default() -> Self {
262        Self {
263            start_number: 1,
264            style: ListNumberStyle::default(),
265            delim: ListNumberDelim::default(),
266        }
267    }
268}
269
270#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
271#[serde(tag = "t", content = "c")]
272pub enum ListNumberStyle {
273    DefaultStyle,
274    Example,
275    Decimal,
276    LowerRoman,
277    UpperRoman,
278    LowerAlpha,
279    UpperAlpha,
280}
281
282impl Default for ListNumberStyle {
283    fn default() -> Self {
284        Self::DefaultStyle
285    }
286}
287
288#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
289#[serde(tag = "t", content = "c")]
290pub enum ListNumberDelim {
291    DefaultDelim,
292    Period,
293    OneParen,
294    TwoParens,
295}
296
297impl Default for ListNumberDelim {
298    fn default() -> Self {
299        Self::DefaultDelim
300    }
301}
302
303#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
304pub struct Format(pub String);
305
306#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq, Default)]
307pub struct Attr {
308    pub identifier: String,
309    pub classes: Vec<String>,
310    pub attributes: Vec<(String, String)>,
311}
312
313#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
314#[serde(tag = "t", content = "c")]
315pub enum QuoteType {
316    SingleQuote,
317    DoubleQuote,
318}
319
320#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq)]
321pub struct Target {
322    pub url: String,
323    pub title: String,
324}
325
326#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
327#[serde(tag = "t", content = "c")]
328pub enum MathType {
329    DisplayMath,
330    InlineMath,
331}
332
333#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
334#[serde(rename_all = "camelCase")]
335pub struct Citation {
336    pub citation_id: String,
337    pub citation_prefix: Vec<Inline>,
338    pub citation_suffix: Vec<Inline>,
339    pub citation_mode: CitationMode,
340    pub citation_note_num: i32,
341    pub citation_hash: i32,
342}
343
344#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
345#[serde(tag = "t", content = "c")]
346pub enum CitationMode {
347    AuthorInText,
348    SuppressAuthor,
349    NormalCitation,
350}
351
352#[cfg(test)]
353mod tests {
354    use super::*;
355    use serde_json::json;
356
357    #[test]
358    fn version() {
359        assert!(serde_json::from_value::<Pandoc>(json!({
360            "pandoc-api-version": PANDOC_API_VERSION,
361            "meta": {},
362            "blocks": [],
363        }))
364        .is_ok());
365
366        assert!(serde_json::from_value::<Pandoc>(json!({
367            "pandoc-api-version": [],
368            "meta": {},
369            "blocks": [],
370        }))
371        .is_err());
372
373        assert!(serde_json::from_value::<Pandoc>(json!({
374            "pandoc-api-version": [PANDOC_API_VERSION[0], PANDOC_API_VERSION[1] + 1],
375            "meta": {},
376            "blocks": [],
377        }))
378        .is_err());
379    }
380}