pandoc_ast 0.2.1

deserializes and serializes pandoc ast json
Documentation
pub use std::collections::BTreeMap as Map;
use serde::{Serialize, Serializer};
pub type Int = i64;
pub type Double = f64;

/// the root object of a pandoc document
#[derive(Serialize, Deserialize, Debug)]
pub struct Pandoc(pub Meta, pub Vec<Block>);

/// Metadata for the document: title, authors, date.
#[derive(Serialize, Deserialize, Debug)]
#[allow(non_snake_case)]
pub struct Meta {
    pub unMeta: Map<String, MetaValue>,
}

#[derive(Deserialize, Debug)]
pub enum MetaValue {
    MetaMap(Map<String, Box<MetaValue>>),
    MetaList(Vec<MetaValue>),
    MetaBool(bool),
    MetaString(String),
    MetaInlines(Vec<Inline>),
    MetaBlocks(Vec<Block>),
}

#[derive(Serialize)]
struct Helper<T: Serialize> {
    t: &'static str,
    c: T,
}

macro_rules! seq {
    ($ser:expr, $var:expr, $vec:expr) => (
        Helper {
            t: $var,
            c: $vec,
        }.serialize($ser)
    )
}

impl Serialize for MetaValue {
    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error> where S: Serializer {
        use self::MetaValue::*;
        match *self {
            MetaMap(ref val) => seq!(ser, "MetaMap", val),
            MetaList(ref val) => seq!(ser, "MetaList", val),
            MetaBool(ref val) => seq!(ser, "MetaBool", val),
            MetaString(ref val) => seq!(ser, "MetaString", val),
            MetaInlines(ref val) => seq!(ser, "MetaInlines", val),
            MetaBlocks(ref val) => seq!(ser, "MetaBlocks", val),
        }
    }
}

/// Structured text like tables and lists
#[derive(Deserialize, Debug)]
pub enum Block {
    /// Plain text, not a paragraph
    Plain(Vec<Inline>),
    /// Paragraph
    Para(Vec<Inline>),
    /// Code block (literal) with attributes
    CodeBlock(Attr, String),
    RawBlock(Format, String),
    /// Block quote (list of blocks)
    BlockQuote(Vec<Block>),
    /// Ordered list (attributes and a list of items, each a list of blocks)
    OrderedList(ListAttributes, Vec<Vec<Block>>),
    /// Bullet list (list of items, each a list of blocks)
    BulletList(Vec<Vec<Block>>),
    /// 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)
    DefinitionList(Vec<(Vec<Inline>, Vec<Vec<Block>>)>),
    /// Header - level (integer) and text (inlines)
    Header(Int, Attr, Vec<Inline>),
    HorizontalRule,
    /// Table, with caption, column alignments (required), relative column widths (0 = default),
    /// column headers (each a list of blocks), and rows (each a list of lists of blocks)
    Table(Vec<Inline>, Vec<Alignment>, Vec<Double>, Vec<TableCell>, Vec<Vec<TableCell>>),
    /// Generic block container with attributes
    Div(Attr, Vec<Block>),
    /// Nothing
    Null,
}

impl Serialize for Block {
    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error> where S: Serializer {
        use self::Block::*;
        match *self {
            Plain(ref val) => seq!(ser, "Plain", val),
            Para(ref val) => seq!(ser, "Para", val),
            CodeBlock(ref val, ref val2) => seq!(ser, "CodeBlock", (val, val2)),
            RawBlock(ref val, ref val2) => seq!(ser, "RawBlock", (val, val2)),
            BlockQuote(ref val) => seq!(ser, "BlockQuote", val),
            OrderedList(ref val, ref val2) => seq!(ser, "OrderedList", (val, val2)),
            BulletList(ref val) => seq!(ser, "BulletList", val),
            DefinitionList(ref val) => seq!(ser, "DefinitionList", val),
            Header(ref val, ref val2, ref val3) => seq!(ser, "Header", (val, val2, val3)),
            HorizontalRule => seq!(ser, "HorizontalRule", Unit),
            Table(ref val, ref v2, ref v3, ref v4, ref v5) => seq!(ser, "Table", (val, v2, v3, v4, v5)),
            Div(ref val, ref val2) => seq!(ser, "Div", (val, val2)),
            Null => seq!(ser, "Null", Unit),
        }
    }
}

/// a single formatting item like bold, italic or hyperlink
#[derive(Deserialize, Debug)]
pub enum Inline {
    /// Text
    Str(String),
    /// Emphasized text
    Emph(Vec<Inline>),
    /// Strongly emphasized text
    Strong(Vec<Inline>),
    Strikeout(Vec<Inline>),
    Superscript(Vec<Inline>),
    Subscript(Vec<Inline>),
    SmallCaps(Vec<Inline>),
    /// Quoted text
    Quoted(QuoteType,Vec<Inline>),
    /// Citation
    Cite(Vec<Citation>, Vec<Inline>),
    /// Inline code (literal)
    Code(Attr, String),
    /// Inter-word space
    Space,
    /// Hard line break
    LineBreak,
    /// TeX math (literal)
    Math(MathType, String),
    RawInline(Format, String),
    /// Hyperlink: text (list of inlines), target
    Link(Vec<Inline>, Target),
    /// Image: alt text (list of inlines), target
    Image(Vec<Inline>, Target),
    /// Footnote or endnote
    Note(Vec<Block>),
    /// Generic inline container with attributes
    Span(Attr, Vec<Inline>),
}

impl Serialize for Inline {
    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error> where S: Serializer {
        use self::Inline::*;
        match *self {
            Str(ref val) => seq!(ser, "Str", val),
            Emph(ref val) => seq!(ser, "Emph", val),
            Strong(ref val) => seq!(ser, "Strong", val),
            Strikeout(ref val) => seq!(ser, "Strikeout", val),
            Superscript(ref val) => seq!(ser, "Superscript", val),
            Subscript(ref val) => seq!(ser, "Subscript", val),
            SmallCaps(ref val) => seq!(ser, "SmallCaps", val),
            Quoted(ref val, ref val2) => seq!(ser, "Quoted", (val, val2)),
            Cite(ref val, ref val2) => seq!(ser, "Cite", (val, val2)),
            Code(ref val, ref val2) => seq!(ser, "Code", (val, val2)),
            Space => seq!(ser, "Space", Unit),
            LineBreak => seq!(ser, "LineBreak", Unit),
            Math(ref val, ref val2) => seq!(ser, "Math", (val, val2)),
            RawInline(ref val, ref val2) => seq!(ser, "RawInline", (val, val2)),
            Link(ref val, ref val2) => seq!(ser, "Link", (val, val2)),
            Image(ref val, ref val2) => seq!(ser, "Image", (val, val2)),
            Note(ref val) => seq!(ser, "Note", val),
            Span(ref val, ref val2) => seq!(ser, "Span", (val, val2)),
        }
    }
}

/// Alignment of a table column.
#[derive(Deserialize, Debug)]
pub enum Alignment {
    AlignLeft,
    AlignRight,
    AlignCenter,
    AlignDefault,
}

impl Serialize for Alignment {
    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error> where S: Serializer {
        use self::Alignment::*;
        match *self {
            AlignLeft => seq!(ser, "AlignLeft", Unit),
            AlignRight => seq!(ser, "AlignRight", Unit),
            AlignCenter => seq!(ser, "AlignCenter", Unit),
            AlignDefault => seq!(ser, "AlignDefault", Unit),
        }
    }
}

pub type ListAttributes = (Int, ListNumberStyle, ListNumberDelim);

/// Style of list numbers.
#[derive(Deserialize, Debug)]
pub enum ListNumberStyle {
    DefaultStyle,
    Example,
    Decimal,
    LowerRoman,
    UpperRoman,
    LowerAlpha,
    UpperAlpha,
}

impl Serialize for ListNumberStyle {
    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error> where S: Serializer {
        use self::ListNumberStyle::*;
        match *self {
            DefaultStyle => seq!(ser, "DefaultStyle", Unit),
            Example => seq!(ser, "Example", Unit),
            Decimal => seq!(ser, "Decimal", Unit),
            LowerRoman => seq!(ser, "LowerRoman", Unit),
            UpperRoman => seq!(ser, "UpperRoman", Unit),
            LowerAlpha => seq!(ser, "LowerAlpha", Unit),
            UpperAlpha => seq!(ser, "UpperAlpha", Unit),
        }
    }
}

/// Delimiter of list numbers.
#[derive(Deserialize, Debug)]
pub enum ListNumberDelim {
    DefaultDelim,
    Period,
    OneParen,
    TwoParens,
}

impl Serialize for ListNumberDelim {
    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error> where S: Serializer {
        use self::ListNumberDelim::*;
        match *self {
            DefaultDelim => seq!(ser, "DefaultDelim", Unit),
            Period => seq!(ser, "Period", Unit),
            OneParen => seq!(ser, "OneParen", Unit),
            TwoParens => seq!(ser, "TwoParens", Unit),
        }
    }
}

/// Formats for raw blocks
#[derive(Serialize, Deserialize, Debug)]
pub struct Format(pub String);

/// Attributes: identifier, classes, key-value pairs
pub type Attr = (String, Vec<String>, Vec<(String, String)>);

/// Table cells are list of Blocks
pub type TableCell = Vec<Block>;

/// Type of quotation marks to use in Quoted inline.
#[derive(Deserialize, Debug)]
pub enum QuoteType {
    SingleQuote,
    DoubleQuote,
}

impl Serialize for QuoteType {
    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error> where S: Serializer {
        use self::QuoteType::*;
        match *self {
            SingleQuote => seq!(ser, "SingleQuote", Unit),
            DoubleQuote => seq!(ser, "DoubleQuote", Unit),
        }
    }
}

struct Unit;

impl serde::ser::SeqVisitor for Unit {
    fn visit<S>(&mut self, _: &mut S) -> Result<Option<()>, S::Error>
        where S: Serializer {
        Ok(None)
    }
    fn len(&self) -> Option<usize> {
        Some(0)
    }
}

impl Serialize for Unit {
    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error> where S: Serializer {
        ser.visit_seq(Unit)
    }
}

/// Link target (URL, title).
pub type Target = (String, String);

/// Type of math element (display or inline).
#[derive(Deserialize, Debug)]
pub enum MathType {
    DisplayMath,
    InlineMath,
}

impl Serialize for MathType {
    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error> where S: Serializer {
        use self::MathType::*;
        match *self {
            DisplayMath => seq!(ser, "DisplayMath", Unit),
            InlineMath => seq!(ser, "InlineMath", Unit),
        }
    }
}

#[derive(Serialize, Deserialize, Debug)]
#[allow(non_snake_case)]
pub struct Citation {
    pub citationId: String,
    pub citationPrefix: Vec<Inline>,
    pub citationSuffix: Vec<Inline>,
    pub citationMode: CitationMode,
    pub citationNoteNum: Int,
    pub citationHash: Int,
}

#[derive(Deserialize, Debug)]
pub enum CitationMode {
    AuthorInText,
    SuppressAuthor,
    NormalCitation,
}

impl Serialize for CitationMode {
    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error> where S: Serializer {
        use self::CitationMode::*;
        match *self {
            AuthorInText => seq!(ser, "AuthorInText", Unit),
            SuppressAuthor => seq!(ser, "SuppressAuthor", Unit),
            NormalCitation => seq!(ser, "NormalCitation", Unit),
        }
    }
}
use serde_json::{Value, from_str, to_string, from_value};

fn pandoc_to_serde(data: &mut Value) {
    match *data {
        Value::Array(ref mut vec) => {
            for el in vec {
                pandoc_to_serde(el);
            }
        }
        Value::Object(ref mut map) => {
            if map.len() != 2 || !map.contains_key("c") || !map.contains_key("t") {
                for (_, v) in map {
                    pandoc_to_serde(v);
                }
                return
            }
            let t = map.remove("t").unwrap();
            if let Value::String(s) = t {
                let mut c = map.remove("c").unwrap();
                pandoc_to_serde(&mut c);
                map.insert(s, c);
            } else {
                unimplemented!()
            }
        }
        _ => {}
    }
}

/// deserialized a json string to a Pandoc object, passes it to the closure/function
/// and serializes the result back into a string
pub fn filter<F: FnOnce(Pandoc)->Pandoc>(json: String, f: F) -> String {
    let mut data: Value = from_str(&json).ok().expect("invalid json");
    pandoc_to_serde(&mut data);
    let data = from_value(data).ok().expect("deserialization failed");
    let data = f(data);
    to_string(&data).ok().expect("serialization failed")
}