diff options
| -rw-r--r-- | Cargo.toml | 1 | ||||
| -rw-r--r-- | src/document_tree/attribute_types.rs | 16 | ||||
| -rw-r--r-- | src/document_tree/elements.rs | 25 | ||||
| -rw-r--r-- | src/document_tree/extra_attributes.rs | 117 |
4 files changed, 100 insertions, 59 deletions
@@ -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>, +}); |
