aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.toml1
-rw-r--r--src/document_tree/attribute_types.rs16
-rw-r--r--src/document_tree/elements.rs25
-rw-r--r--src/document_tree/extra_attributes.rs117
4 files changed, 100 insertions, 59 deletions
diff --git a/Cargo.toml b/Cargo.toml
index df0a51f..103576e 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -29,6 +29,7 @@ unicode_categories = '0.1.1'
pest = { git = 'https://github.com/pest-parser/pest' }
pest_derive = { git = 'https://github.com/pest-parser/pest' }
serde = '1.0.80'
+serde_derive = '1.0.80'
serde_json = '1.0.33'
quicli = '0.3.1'
diff --git a/src/document_tree/attribute_types.rs b/src/document_tree/attribute_types.rs
index 83ce618..1f3c466 100644
--- a/src/document_tree/attribute_types.rs
+++ b/src/document_tree/attribute_types.rs
@@ -1,4 +1,6 @@
-#[derive(Debug)]
+use serde_derive::Serialize;
+
+#[derive(Debug,Serialize)]
pub enum EnumeratedListType {
Arabic,
LowerAlpha,
@@ -7,17 +9,17 @@ pub enum EnumeratedListType {
UpperRoman,
}
-#[derive(Debug)]
+#[derive(Debug,Serialize)]
pub enum FixedSpace { Default, Preserve } // yes, default really is not “Default”
impl Default for FixedSpace { fn default() -> FixedSpace { FixedSpace::Preserve } }
-#[derive(Debug)] pub enum AlignH { Left, Center, Right}
-#[derive(Debug)] pub enum AlignHV { Top, Middle, Bottom, Left, Center, Right }
+#[derive(Debug,Serialize)] pub enum AlignH { Left, Center, Right}
+#[derive(Debug,Serialize)] pub enum AlignHV { Top, Middle, Bottom, Left, Center, Right }
-#[derive(Debug)] pub struct ID(String);
-#[derive(Debug)] pub struct NameToken(String);
+#[derive(Debug,Serialize)] pub struct ID(String);
+#[derive(Debug,Serialize)] pub struct NameToken(String);
-#[derive(Debug)]
+#[derive(Debug,Serialize)]
pub enum Measure {
Pixel(usize),
Em(usize),
diff --git a/src/document_tree/elements.rs b/src/document_tree/elements.rs
index 681c52e..900d1d4 100644
--- a/src/document_tree/elements.rs
+++ b/src/document_tree/elements.rs
@@ -2,8 +2,9 @@ use url::Url;
use serde::{
Serialize,
Serializer,
- ser::{SerializeStruct},
+ ser::SerializeStruct,
};
+use serde_derive::Serialize;
use super::extra_attributes::{self,ExtraAttributes};
use super::element_categories::*;
@@ -81,15 +82,13 @@ macro_rules! impl_serialize {
($name: ident, $extra: ident, $childtype: ident) => {
impl Serialize for $name {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
- #[allow(unused_mut)]
- let mut state = serializer.serialize_struct(stringify!($name), 3)?;
- // TODO: common attrs
- impl_cond__! { $extra =>
-
- }
- impl_cond__! { $childtype =>
- state.serialize_field("children", self.children())?;
- }
+ 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__!($childtype ? self.children()))?;
state.end()
}
}
@@ -97,8 +96,8 @@ macro_rules! impl_serialize {
}
macro_rules! impl_cond__ {
- (__ => $($b:tt)*) => {};
- ($thing: ident => $($b:tt)*) => { $($b)* };
+ (__ ? $($b:tt)*) => { None::<Option<()>> };
+ ($thing: ident ? $($b:tt)*) => { $($b)* };
}
macro_rules! impl_elem {
@@ -134,7 +133,7 @@ macro_rules! impl_elems { ( $( ($($args:tt)*) )* ) => (
)}
-#[derive(Default,Debug)]
+#[derive(Default,Debug,Serialize)]
pub struct Document { children: Vec<StructuralSubElement> }
impl_children!(Document, StructuralSubElement);
diff --git a/src/document_tree/extra_attributes.rs b/src/document_tree/extra_attributes.rs
index d73013e..9cd097d 100644
--- a/src/document_tree/extra_attributes.rs
+++ b/src/document_tree/extra_attributes.rs
@@ -1,5 +1,11 @@
use url::Url;
+use serde::{
+ Serialize,
+ Serializer,
+ ser::SerializeStruct,
+};
+
use super::attribute_types::{FixedSpace,ID,NameToken,AlignHV,AlignH,Measure,EnumeratedListType};
pub trait ExtraAttributes<A> {
@@ -8,51 +14,84 @@ pub trait ExtraAttributes<A> {
fn extra_mut(&mut self) -> &mut A;
}
-#[derive(Default,Debug)] pub struct Address { pub space: FixedSpace }
-#[derive(Default,Debug)] pub struct LiteralBlock { pub space: FixedSpace }
-#[derive(Default,Debug)] pub struct DoctestBlock { pub space: FixedSpace }
-#[derive(Default,Debug)] pub struct SubstitutionDefinition { pub ltrim: Option<bool>, pub rtrim: Option<bool> }
-#[derive(Default,Debug)] pub struct Comment { pub space: FixedSpace }
-#[derive(Default,Debug)] pub struct Target { pub refuri: Option<Url>, pub refid: Option<ID>, pub refname: Vec<NameToken>, pub anonymous: Option<bool> }
-#[derive(Default,Debug)] pub struct Raw { pub space: FixedSpace, pub format: Vec<NameToken> }
-#[derive(Debug)]
-pub struct Image {
- pub align: Option<AlignHV>,
- pub uri: Url,
- pub alt: Option<String>,
- pub height: Option<Measure>,
- pub width: Option<Measure>,
- pub scale: Option<f64>,
+macro_rules! count {
+ () => (0usize);
+ ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
+}
+
+macro_rules! ser_url {
+ ($self:ident, refuri ) => { $self.refuri.as_ref().map(|uri| uri.to_string()) };
+ ($self:ident, uri ) => { $self.uri.to_string() };
+ ($self:ident, $param:ident) => { $self.$param };
}
+macro_rules! impl_extra {
+ ( $name:ident { $( $param:ident : $type:ty ),* $(,)* } ) => (
+ impl_extra!(
+ #[derive(Default,Debug)]
+ $name { $( $param : $type, )* }
+ );
+ );
+ ( $(#[$attr:meta])+ $name:ident { $( $param:ident : $type:ty ),* $(,)* } ) => (
+ $(#[$attr])+
+ pub struct $name {
+ $( pub $param : $type, )*
+ }
+
+ impl Serialize for $name {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
+ #[allow(unused_mut)]
+ let mut state = serializer.serialize_struct(stringify!($name), count!($($param)*))?;
+ $( state.serialize_field(stringify!($param), &ser_url!(self, $param))?; )*
+ state.end()
+ }
+ }
+ );
+}
+
+impl_extra!(Address { space: FixedSpace });
+impl_extra!(LiteralBlock { space: FixedSpace });
+impl_extra!(DoctestBlock { space: FixedSpace });
+impl_extra!(SubstitutionDefinition { ltrim: Option<bool>, rtrim: Option<bool> });
+impl_extra!(Comment { space: FixedSpace });
+impl_extra!(Target { refuri: Option<Url>, refid: Option<ID>, refname: Vec<NameToken>, anonymous: Option<bool> });
+impl_extra!(Raw { space: FixedSpace, format: Vec<NameToken> });
+impl_extra!(#[derive(Debug)] Image {
+ align: Option<AlignHV>,
+ uri: Url,
+ alt: Option<String>,
+ height: Option<Measure>,
+ width: Option<Measure>,
+ scale: Option<f64>,
+});
+
//bools usually are XML yesorno. “auto” however either exists and is set to something random like “1” or doesn’t exist
-#[derive(Default,Debug)] pub struct BulletList { pub bullet: Option<String> }
-#[derive(Default,Debug)] pub struct EnumeratedList { pub enumtype: Option<EnumeratedListType>, pub prefix: Option<String>, pub suffix: Option<String> }
+impl_extra!(BulletList { bullet: Option<String> });
+impl_extra!(EnumeratedList { enumtype: Option<EnumeratedListType>, prefix: Option<String>, suffix: Option<String> });
-#[derive(Default,Debug)] pub struct Footnote { pub backrefs: Vec<ID>, pub auto: Option<bool> }
-#[derive(Default,Debug)] pub struct Citation { pub backrefs: Vec<ID> }
-#[derive(Default,Debug)] pub struct SystemMessage { pub backrefs: Vec<ID>, pub level: Option<usize>, pub line: Option<usize>, pub type_: Option<NameToken> }
-#[derive(Default,Debug)] pub struct Figure { pub align: Option<AlignH>, pub width: Option<usize> }
-#[derive(Default,Debug)] pub struct Table; //TODO
+impl_extra!(Footnote { backrefs: Vec<ID>, auto: Option<bool> });
+impl_extra!(Citation { backrefs: Vec<ID> });
+impl_extra!(SystemMessage { backrefs: Vec<ID>, level: Option<usize>, line: Option<usize>, type_: Option<NameToken> });
+impl_extra!(Figure { align: Option<AlignH>, width: Option<usize> });
+impl_extra!(Table {}); //TODO
-#[derive(Default,Debug)] pub struct OptionArgument { pub delimiter: Option<String> }
+impl_extra!(OptionArgument { delimiter: Option<String> });
-#[derive(Default,Debug)] pub struct Reference { pub name: Option<String>, pub refuri: Option<Url>, pub refid: Option<ID>, pub refname: Vec<NameToken> }
-#[derive(Default,Debug)] pub struct FootnoteReference { pub refid: Option<ID>, pub refname: Vec<NameToken>, pub auto: Option<bool> }
-#[derive(Default,Debug)] pub struct CitationReference { pub refid: Option<ID>, pub refname: Vec<NameToken> }
-#[derive(Default,Debug)] pub struct SubstitutionReference { pub refname: Vec<NameToken> }
-#[derive(Default,Debug)] pub struct Problematic { pub refid: Option<ID> }
+impl_extra!(Reference { name: Option<String>, refuri: Option<Url>, refid: Option<ID>, refname: Vec<NameToken> });
+impl_extra!(FootnoteReference { refid: Option<ID>, refname: Vec<NameToken>, auto: Option<bool> });
+impl_extra!(CitationReference { refid: Option<ID>, refname: Vec<NameToken> });
+impl_extra!(SubstitutionReference { refname: Vec<NameToken> });
+impl_extra!(Problematic { refid: Option<ID> });
//also have non-inline versions. Inline image is no figure child, inline target has content
-#[derive(Default,Debug)] pub struct TargetInline { pub refuri: Option<Url>, pub refid: Option<ID>, pub refname: Vec<NameToken>, pub anonymous: Option<bool> }
-#[derive(Default,Debug)] pub struct RawInline { pub space: FixedSpace, pub format: Vec<NameToken> }
-#[derive(Debug)]
-pub struct ImageInline {
- pub align: Option<AlignHV>,
- pub uri: Url,
- pub alt: Option<String>,
- pub height: Option<Measure>,
- pub width: Option<Measure>,
- pub scale: Option<f64>,
-}
+impl_extra!(TargetInline { refuri: Option<Url>, refid: Option<ID>, refname: Vec<NameToken>, anonymous: Option<bool> });
+impl_extra!(RawInline { space: FixedSpace, format: Vec<NameToken> });
+impl_extra!(#[derive(Debug)] ImageInline {
+ align: Option<AlignHV>,
+ uri: Url,
+ alt: Option<String>,
+ height: Option<Measure>,
+ width: Option<Measure>,
+ scale: Option<f64>,
+});