1use 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(Vec<Inline>),
84 Para(Vec<Inline>),
86 LineBlock(Vec<Vec<Inline>>),
88 CodeBlock(Attr, String),
90 RawBlock(Format, String),
92 BlockQuote(Vec<Block>),
94 OrderedList(ListAttributes, Vec<Vec<Block>>),
96 BulletList(Vec<Vec<Block>>),
98 DefinitionList(Vec<(Vec<Inline>, Vec<Vec<Block>>)>),
100 Header(i32, Attr, Vec<Inline>),
102 HorizontalRule,
104 Table(Table),
106 Figure(Attr, Caption, Vec<Block>),
108 Div(Attr, Vec<Block>),
110 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 Str(String),
129 Emph(Vec<Inline>),
131 Underline(Vec<Inline>),
133 Strong(Vec<Inline>),
135 Strikeout(Vec<Inline>),
137 Superscript(Vec<Inline>),
139 Subscript(Vec<Inline>),
141 SmallCaps(Vec<Inline>),
143 Quoted(QuoteType, Vec<Inline>),
145 Cite(Vec<Citation>, Vec<Inline>),
147 Code(Attr, String),
149 Space,
151 SoftBreak,
153 LineBreak,
155 Math(MathType, String),
157 RawInline(Format, String),
159 Link(Attr, Vec<Inline>, Target),
161 Image(Attr, Vec<Inline>, Target),
163 Note(Vec<Block>),
165 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}