aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPhilipp A2018-11-21 21:28:59 +0100
committerPhilipp A2018-11-21 21:28:59 +0100
commit37ee18111c4ad76076ab973a4f38544ec9974050 (patch)
tree0fdfc2eb25d0e9a7e69d2257ed11daeee381e4e5
parent32d660c23ca7d44da44112187f2efb18fa4077ed (diff)
downloadrust-rst-37ee18111c4ad76076ab973a4f38544ec9974050.tar.bz2
Automate serialization
-rw-r--r--src/document_tree/elements.rs80
-rw-r--r--src/parser.rs117
-rw-r--r--src/parser/conversion.rs99
-rw-r--r--src/parser/pest_rst.rs5
4 files changed, 149 insertions, 152 deletions
diff --git a/src/document_tree/elements.rs b/src/document_tree/elements.rs
index a5519ce..99772b2 100644
--- a/src/document_tree/elements.rs
+++ b/src/document_tree/elements.rs
@@ -1,14 +1,15 @@
-use url::Url;
-use serde::{
- Serialize,
- Serializer,
- ser::SerializeStruct,
-};
use serde_derive::Serialize;
+use url::Url;
use super::extra_attributes::{self,ExtraAttributes};
use super::element_categories::*;
+fn serialize_opt_url<S>(url_opt: &Option<Url>, serializer: S) -> Result<S::Ok, S::Error> where S: serde::ser::Serializer {
+ match url_opt {
+ Some(ref url) => serializer.serialize_some(url.as_str()),
+ None => serializer.serialize_none(),
+ }
+}
//-----------------\\
//Element hierarchy\\
@@ -25,10 +26,11 @@ pub trait Element {
fn classes_mut(&mut self) -> &mut Vec<String>;
}
-#[derive(Default,Debug)]
+#[derive(Debug,Default,Serialize)]
pub struct CommonAttributes {
ids: Vec<String>,
names: Vec<String>,
+ #[serde(serialize_with = "serialize_opt_url")]
source: Option<Url>,
classes: Vec<String>,
//left out dupnames
@@ -69,62 +71,56 @@ macro_rules! impl_extra { ($name:ident) => (
macro_rules! impl_new {(
$(#[$attr:meta])*
- pub struct $name:ident { $( $field:ident : $typ:path ),*
-}) => (
+ pub struct $name:ident { $(
+ $(#[$fattr:meta])*
+ $field:ident : $typ:path
+ ),* $(,)* }
+) => (
$(#[$attr])*
- pub struct $name { $( $field: $typ, )* }
+ #[derive(Debug,Serialize)]
+ pub struct $name { $(
+ $(#[$fattr])* $field: $typ,
+ )* }
impl $name {
pub fn new( $( $field: $typ, )* ) -> $name { $name { $( $field: $field, )* } }
}
)}
-macro_rules! impl_serialize {
- ($name: ident, $extra: ident, $children: ident) => {
- impl Serialize for $name {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
- let mut state = serializer.serialize_struct(stringify!($name), 6)?;
- state.serialize_field("ids", self.ids())?;
- state.serialize_field("names", self.names())?;
- state.serialize_field("source", &self.source().as_ref().map(|uri| uri.to_string()))?;
- state.serialize_field("classes", self.classes())?;
- state.serialize_field("extra", &impl_cond!($extra ? self.extra() ))?;
- state.serialize_field("children", &impl_cond!($children ? self.children()))?;
- state.end()
- }
- }
- };
-}
-
-macro_rules! impl_cond {
- (false ? $($b:tt)*) => { () };
- (true ? $($b:tt)*) => { $($b)* };
-}
-
macro_rules! impl_elem {
($name:ident) => {
- impl_new!(#[derive(Default,Debug)] pub struct $name { common: CommonAttributes });
+ impl_new!(#[derive(Default)] pub struct $name {
+ #[serde(flatten)] common: CommonAttributes,
+ });
impl_element!($name);
- impl_serialize!($name, false, false);
};
($name:ident; +) => {
- impl_new!(#[derive(Default,Debug)] pub struct $name { common: CommonAttributes, extra: extra_attributes::$name });
+ impl_new!(#[derive(Default)] pub struct $name {
+ #[serde(flatten)] common: CommonAttributes,
+ #[serde(flatten)] extra: extra_attributes::$name,
+ });
impl_element!($name); impl_extra!($name);
- impl_serialize!($name, true, false);
};
($name:ident; *) => { //same as above with no default
- impl_new!(#[derive(Debug)] pub struct $name { common: CommonAttributes, extra: extra_attributes::$name });
+ impl_new!(pub struct $name {
+ #[serde(flatten)] common: CommonAttributes,
+ #[serde(flatten)] extra: extra_attributes::$name
+ });
impl_element!($name); impl_extra!($name);
- impl_serialize!($name, true, false);
};
($name:ident, $childtype:ident) => {
- impl_new!(#[derive(Default,Debug)] pub struct $name { common: CommonAttributes, children: Vec<$childtype> });
+ impl_new!(#[derive(Default)] pub struct $name {
+ #[serde(flatten)] common: CommonAttributes,
+ children: Vec<$childtype>,
+ });
impl_element!($name); impl_children!($name, $childtype);
- impl_serialize!($name, false, true);
};
($name:ident, $childtype:ident; +) => {
- impl_new!(#[derive(Default,Debug)] pub struct $name { common: CommonAttributes, extra: extra_attributes::$name, children: Vec<$childtype> });
+ impl_new!(#[derive(Default)] pub struct $name {
+ #[serde(flatten)] common: CommonAttributes,
+ #[serde(flatten)] extra: extra_attributes::$name,
+ children: Vec<$childtype>,
+ });
impl_element!($name); impl_extra!($name); impl_children!($name, $childtype);
- impl_serialize!($name, true, true);
};
}
diff --git a/src/parser.rs b/src/parser.rs
index a75d2a1..893f635 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -1,127 +1,24 @@
pub mod token;
+pub mod conversion;
+mod pest_rst;
#[cfg(test)]
pub mod tests;
-mod pest_rst {
- use pest_derive::Parser;
-
- #[derive(Parser)]
- #[grammar = "rst.pest"]
- pub struct RstParser;
-}
-use self::pest_rst::Rule;
-
use std::io::Write;
-use url::Url;
use failure::Error;
-use failure_derive::Fail;
use pest::Parser;
-use crate::document_tree::{
- HasChildren,
- elements::{
- Document,
- Title,
- Paragraph,
- Target,
- Attention, Hint, Note, Caution, Danger, Error as ErrorEl, Important, Tip, Warning
- },
- element_categories::{
- StructuralSubElement,
- SubStructure,
- BodyElement,
- },
- attribute_types::ID,
- extra_attributes,
-};
-
-
-#[derive(Debug, Fail)]
-enum ConversionError {
- #[fail(display = "unknown rule: {:?}", rule)]
- UnknownRuleError {
- rule: Rule,
- },
-}
-
-
-fn convert_ssubel(pair: pest::iterators::Pair<Rule>) -> Result<StructuralSubElement, Error> {
- // TODO: This is just a proof of concep. Keep closely to DTD in final version!
- match pair.as_rule() {
- Rule::title => Ok(convert_title(pair).into()),
- Rule::paragraph => Ok(to_ssub(Paragraph::with_children(vec![pair.as_str().into()]))),
- Rule::target => Ok(to_ssub(convert_target(pair)?)),
- Rule::admonition_gen => Ok(to_ssub(convert_admonition_gen(pair)?)),
- rule => Err(ConversionError::UnknownRuleError { rule }.into()),
- }
-}
-
+use crate::document_tree::elements::Document;
-fn to_ssub<E>(elem: E) -> StructuralSubElement where E: Into<BodyElement> {
- let belm: BodyElement = elem.into();
- let sstruc: SubStructure = belm.into();
- sstruc.into()
-}
-
-
-fn convert_title(pair: pest::iterators::Pair<pest_rst::Rule>) -> Title {
- let mut title: Option<&str> = None;
- let mut _adornment_char: Option<char> = None;
- for p in pair.into_inner() {
- match p.as_rule() {
- Rule::line => title = Some(p.as_str()),
- Rule::adornments => _adornment_char = Some(p.as_str().chars().next().expect("Empty adornment?")),
- rule => panic!("Unexpected rule in title: {:?}", rule),
- };
- }
- // TODO adornment char
- Title::with_children(vec![
- title.expect("No text in title").into()
- ])
-}
-
-fn convert_target(pair: pest::iterators::Pair<pest_rst::Rule>) -> Result<Target, Error> {
- let mut attrs = extra_attributes::Target {
- anonymous: false,
- ..Default::default()
- };
- for p in pair.into_inner() {
- match p.as_rule() {
- // TODO: or is it refnames?
- Rule::target_name_uq | Rule::target_name_qu => attrs.refid = Some(ID(p.as_str().to_owned())),
- Rule::link_target => attrs.refuri = Some(Url::parse(p.as_str())?),
- rule => panic!("Unexpected rule in target: {:?}", rule),
- }
- }
- Ok(Target::new(Default::default(), attrs))
-}
-
-fn convert_admonition_gen(pair: pest::iterators::Pair<pest_rst::Rule>) -> Result<BodyElement, Error> {
- let mut iter = pair.into_inner();
- let typ = iter.next().unwrap().as_str();
- // TODO: in reality it contains body elements.
- let children: Vec<BodyElement> = iter.map(|p| Paragraph::with_children(vec![p.as_str().into()]).into()).collect();
- Ok(match typ {
- "attention" => Attention::with_children(children).into(),
- "hint" => Hint::with_children(children).into(),
- "note" => Note::with_children(children).into(),
- "caution" => Caution::with_children(children).into(),
- "danger" => Danger::with_children(children).into(),
- "error" => ErrorEl::with_children(children).into(),
- "important" => Important::with_children(children).into(),
- "tip" => Tip::with_children(children).into(),
- "warning" => Warning::with_children(children).into(),
- typ => panic!("Unknown admontion type {}!", typ),
- })
-}
+use self::pest_rst::{RstParser,Rule};
+use self::conversion::convert_document;
/// tokens to Document tree. resolves sections, but not references
pub fn parse(source: &str) -> Result<Document, Error> {
- let pairs = pest_rst::RstParser::parse(pest_rst::Rule::document, source)?;
- let structural_elems = pairs.map(convert_ssubel).collect::<Result<_, _>>()?;
- Ok(Document::with_children(structural_elems))
+ let pairs = RstParser::parse(Rule::document, source)?;
+ convert_document(pairs)
}
diff --git a/src/parser/conversion.rs b/src/parser/conversion.rs
new file mode 100644
index 0000000..5fc9605
--- /dev/null
+++ b/src/parser/conversion.rs
@@ -0,0 +1,99 @@
+use url::Url;
+use failure::Error;
+use failure_derive::Fail;
+use pest::iterators::{Pairs,Pair};
+
+use crate::document_tree::{
+ HasChildren,
+ elements as e,
+ element_categories as c,
+ attribute_types::ID,
+ extra_attributes,
+};
+
+use super::pest_rst::Rule;
+
+#[derive(Debug, Fail)]
+enum ConversionError {
+ #[fail(display = "unknown rule: {:?}", rule)]
+ UnknownRuleError {
+ rule: Rule,
+ },
+}
+
+
+pub fn convert_document(pairs: Pairs<Rule>) -> Result<e::Document, Error> {
+ let structural_elems = pairs.map(convert_ssubel).collect::<Result<_,_>>()?;
+ Ok(e::Document::with_children(structural_elems))
+}
+
+
+fn convert_ssubel(pair: Pair<Rule>) -> Result<c::StructuralSubElement, Error> {
+ // TODO: This is just a proof of concep. Keep closely to DTD in final version!
+ match pair.as_rule() {
+ Rule::title => Ok(convert_title(pair).into()),
+ Rule::paragraph => Ok(to_ssub(e::Paragraph::with_children(vec![pair.as_str().into()]))),
+ Rule::target => Ok(to_ssub(convert_target(pair)?)),
+ Rule::admonition_gen => Ok(to_ssub(convert_admonition_gen(pair)?)),
+ rule => Err(ConversionError::UnknownRuleError { rule }.into()),
+ }
+}
+
+
+fn to_ssub<E>(elem: E) -> c::StructuralSubElement where E: Into<c::BodyElement> {
+ let belm: c::BodyElement = elem.into();
+ let sstruc: c::SubStructure = belm.into();
+ sstruc.into()
+}
+
+
+fn convert_title(pair: Pair<Rule>) -> e::Title {
+ let mut title: Option<&str> = None;
+ let mut _adornment_char: Option<char> = None;
+ for p in pair.into_inner() {
+ match p.as_rule() {
+ Rule::line => title = Some(p.as_str()),
+ Rule::adornments => _adornment_char = Some(p.as_str().chars().next().expect("Empty adornment?")),
+ rule => panic!("Unexpected rule in title: {:?}", rule),
+ };
+ }
+ // TODO adornment char
+ e::Title::with_children(vec![
+ title.expect("No text in title").into()
+ ])
+}
+
+fn convert_target(pair: Pair<Rule>) -> Result<e::Target, Error> {
+ let mut attrs = extra_attributes::Target {
+ anonymous: false,
+ ..Default::default()
+ };
+ for p in pair.into_inner() {
+ match p.as_rule() {
+ // TODO: or is it refnames?
+ Rule::target_name_uq | Rule::target_name_qu => attrs.refid = Some(ID(p.as_str().to_owned())),
+ Rule::link_target => attrs.refuri = Some(Url::parse(p.as_str())?),
+ rule => panic!("Unexpected rule in target: {:?}", rule),
+ }
+ }
+ Ok(e::Target::new(Default::default(), attrs))
+}
+
+fn convert_admonition_gen(pair: Pair<Rule>) -> Result<c::BodyElement, Error> {
+ let mut iter = pair.into_inner();
+ let typ = iter.next().unwrap().as_str();
+ // TODO: in reality it contains body elements.
+ let children: Vec<c::BodyElement> = iter.map(|p| e::Paragraph::with_children(vec![p.as_str().into()]).into()).collect();
+ Ok(match typ {
+ "attention" => e::Attention::with_children(children).into(),
+ "hint" => e::Hint::with_children(children).into(),
+ "note" => e::Note::with_children(children).into(),
+ "caution" => e::Caution::with_children(children).into(),
+ "danger" => e::Danger::with_children(children).into(),
+ "error" => e::Error::with_children(children).into(),
+ "important" => e::Important::with_children(children).into(),
+ "tip" => e::Tip::with_children(children).into(),
+ "warning" => e::Warning::with_children(children).into(),
+ typ => panic!("Unknown admontion type {}!", typ),
+ })
+}
diff --git a/src/parser/pest_rst.rs b/src/parser/pest_rst.rs
new file mode 100644
index 0000000..8c36fc1
--- /dev/null
+++ b/src/parser/pest_rst.rs
@@ -0,0 +1,5 @@
+use pest_derive::Parser;
+
+#[derive(Parser)]
+#[grammar = "rst.pest"]
+pub struct RstParser;