use std::collections::HashMap;
pub use iter::*;
use serde::ser::SerializeStruct;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_tuple::{Deserialize_tuple, Serialize_tuple};
pub mod extra;
mod iter;
const PANDOC_API_VERSION: [i32; 2] = [1, 23];
#[derive(Debug, Clone, PartialEq, Default)]
pub struct Pandoc {
pub blocks: Vec<Block>,
pub meta: HashMap<String, MetaValue>,
}
impl Serialize for Pandoc {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut value = serializer.serialize_struct("Pandoc", 3)?;
value.serialize_field("pandoc-api-version", &PANDOC_API_VERSION)?;
value.serialize_field("meta", &self.meta)?;
value.serialize_field("blocks", &self.blocks)?;
value.end()
}
}
impl<'a> Deserialize<'a> for Pandoc {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'a>,
{
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename = "Pandoc")]
struct Inner {
meta: HashMap<String, MetaValue>,
blocks: Vec<Block>,
#[serde(rename = "pandoc-api-version")]
version: Vec<i32>,
}
let value = Inner::deserialize(deserializer)?;
if value.version.len() < 2
|| value.version[0] != PANDOC_API_VERSION[0]
|| value.version[1] != PANDOC_API_VERSION[1]
{
return Err(serde::de::Error::custom(format!(
"expected pandoc-api-version to start with {},{}",
PANDOC_API_VERSION[0], PANDOC_API_VERSION[1]
)));
}
Ok(Pandoc {
meta: value.meta,
blocks: value.blocks,
})
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "t", content = "c")]
pub enum MetaValue {
MetaMap(HashMap<String, MetaValue>),
MetaList(Vec<MetaValue>),
MetaBool(bool),
MetaString(String),
MetaInlines(Vec<Inline>),
MetaBlocks(Vec<Block>),
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "t", content = "c")]
pub enum Block {
Plain(Vec<Inline>),
Para(Vec<Inline>),
LineBlock(Vec<Vec<Inline>>),
CodeBlock(Attr, String),
RawBlock(Format, String),
BlockQuote(Vec<Block>),
OrderedList(ListAttributes, Vec<Vec<Block>>),
BulletList(Vec<Vec<Block>>),
DefinitionList(Vec<(Vec<Inline>, Vec<Vec<Block>>)>),
Header(i32, Attr, Vec<Inline>),
HorizontalRule,
Table(Table),
Figure(Attr, Caption, Vec<Block>),
Div(Attr, Vec<Block>),
Null,
}
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq, Default)]
pub struct Table {
pub attr: Attr,
pub caption: Caption,
pub colspecs: Vec<ColSpec>,
pub head: TableHead,
pub bodies: Vec<TableBody>,
pub foot: TableFoot,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "t", content = "c")]
pub enum Inline {
Str(String),
Emph(Vec<Inline>),
Underline(Vec<Inline>),
Strong(Vec<Inline>),
Strikeout(Vec<Inline>),
Superscript(Vec<Inline>),
Subscript(Vec<Inline>),
SmallCaps(Vec<Inline>),
Quoted(QuoteType, Vec<Inline>),
Cite(Vec<Citation>, Vec<Inline>),
Code(Attr, String),
Space,
SoftBreak,
LineBreak,
Math(MathType, String),
RawInline(Format, String),
Link(Attr, Vec<Inline>, Target),
Image(Attr, Vec<Inline>, Target),
Note(Vec<Block>),
Span(Attr, Vec<Inline>),
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "t", content = "c")]
pub enum Alignment {
AlignLeft,
AlignRight,
AlignCenter,
AlignDefault,
}
impl Default for Alignment {
fn default() -> Self {
Self::AlignDefault
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "t", content = "c")]
pub enum ColWidth {
ColWidth(f64),
ColWidthDefault,
}
impl Default for ColWidth {
fn default() -> Self {
Self::ColWidthDefault
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
pub struct ColSpec(pub Alignment, pub ColWidth);
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq)]
pub struct Row {
pub attr: Attr,
pub cells: Vec<Cell>,
}
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq, Default)]
pub struct TableHead {
pub attr: Attr,
pub rows: Vec<Row>,
}
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq, Default)]
pub struct TableBody {
pub attr: Attr,
pub row_head_columns: i32,
pub head: Vec<Row>,
pub body: Vec<Row>,
}
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq, Default)]
pub struct TableFoot {
pub attr: Attr,
pub rows: Vec<Row>,
}
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq, Default)]
pub struct Caption {
pub short: Option<Vec<Inline>>,
pub long: Vec<Block>,
}
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq)]
pub struct Cell {
pub attr: Attr,
pub align: Alignment,
pub row_span: i32,
pub col_span: i32,
pub content: Vec<Block>,
}
impl Default for Cell {
fn default() -> Self {
Self {
attr: Default::default(),
align: Default::default(),
row_span: 1,
col_span: 1,
content: Default::default(),
}
}
}
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq)]
pub struct ListAttributes {
pub start_number: i32,
pub style: ListNumberStyle,
pub delim: ListNumberDelim,
}
impl Default for ListAttributes {
fn default() -> Self {
Self {
start_number: 1,
style: ListNumberStyle::default(),
delim: ListNumberDelim::default(),
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "t", content = "c")]
pub enum ListNumberStyle {
DefaultStyle,
Example,
Decimal,
LowerRoman,
UpperRoman,
LowerAlpha,
UpperAlpha,
}
impl Default for ListNumberStyle {
fn default() -> Self {
Self::DefaultStyle
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "t", content = "c")]
pub enum ListNumberDelim {
DefaultDelim,
Period,
OneParen,
TwoParens,
}
impl Default for ListNumberDelim {
fn default() -> Self {
Self::DefaultDelim
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Format(pub String);
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq, Default)]
pub struct Attr {
pub identifier: String,
pub classes: Vec<String>,
pub attributes: Vec<(String, String)>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "t", content = "c")]
pub enum QuoteType {
SingleQuote,
DoubleQuote,
}
#[derive(Serialize_tuple, Deserialize_tuple, Debug, Clone, PartialEq)]
pub struct Target {
pub url: String,
pub title: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "t", content = "c")]
pub enum MathType {
DisplayMath,
InlineMath,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(rename_all = "camelCase")]
pub struct Citation {
pub citation_id: String,
pub citation_prefix: Vec<Inline>,
pub citation_suffix: Vec<Inline>,
pub citation_mode: CitationMode,
pub citation_note_num: i32,
pub citation_hash: i32,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
#[serde(tag = "t", content = "c")]
pub enum CitationMode {
AuthorInText,
SuppressAuthor,
NormalCitation,
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn version() {
assert!(serde_json::from_value::<Pandoc>(json!({
"pandoc-api-version": PANDOC_API_VERSION,
"meta": {},
"blocks": [],
}))
.is_ok());
assert!(serde_json::from_value::<Pandoc>(json!({
"pandoc-api-version": [],
"meta": {},
"blocks": [],
}))
.is_err());
assert!(serde_json::from_value::<Pandoc>(json!({
"pandoc-api-version": [PANDOC_API_VERSION[0], PANDOC_API_VERSION[1] + 1],
"meta": {},
"blocks": [],
}))
.is_err());
}
}