diff options
Diffstat (limited to 'document_tree/src')
| -rw-r--r-- | document_tree/src/attribute_types.rs | 238 | ||||
| -rw-r--r-- | document_tree/src/element_categories.rs | 260 | ||||
| -rw-r--r-- | document_tree/src/element_types.rs | 186 | ||||
| -rw-r--r-- | document_tree/src/elements.rs | 546 | ||||
| -rw-r--r-- | document_tree/src/extra_attributes.rs | 126 | ||||
| -rw-r--r-- | document_tree/src/lib.rs | 74 | ||||
| -rw-r--r-- | document_tree/src/macro_util.rs | 63 | ||||
| -rw-r--r-- | document_tree/src/url.rs | 104 | 
8 files changed, 885 insertions, 712 deletions
| diff --git a/document_tree/src/attribute_types.rs b/document_tree/src/attribute_types.rs index 411b24d..5303c5b 100644 --- a/document_tree/src/attribute_types.rs +++ b/document_tree/src/attribute_types.rs @@ -1,155 +1,201 @@  use std::str::FromStr; -use failure::{Error,bail,format_err}; -use serde_derive::Serialize; +use failure::{bail, format_err, Error};  use regex::Regex; +use serde_derive::Serialize;  use crate::url::Url; -#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] +#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone)]  pub enum EnumeratedListType { -	Arabic, -	LowerAlpha, -	UpperAlpha, -	LowerRoman, -	UpperRoman, +    Arabic, +    LowerAlpha, +    UpperAlpha, +    LowerRoman, +    UpperRoman,  } -#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] -pub enum FixedSpace { Default, Preserve }  // yes, default really is not “Default” -impl Default for FixedSpace { fn default() -> FixedSpace { FixedSpace::Preserve } } +#[derive(Default, Debug, PartialEq, Eq, Hash, Serialize, Clone)] +pub enum FixedSpace { +    Default, +    // yes, default really is not “Default” +    #[default] +    Preserve, +} -#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub enum AlignH { Left, Center, Right} -#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub enum AlignHV { Top, Middle, Bottom, Left, Center, Right } -#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub enum AlignV { Top, Middle, Bottom } +#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone)] +pub enum AlignH { +    Left, +    Center, +    Right, +} +#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone)] +pub enum AlignHV { +    Top, +    Middle, +    Bottom, +    Left, +    Center, +    Right, +} +#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone)] +pub enum AlignV { +    Top, +    Middle, +    Bottom, +} -#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub enum TableAlignH { Left, Right, Center, Justify, Char } -#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub enum TableBorder { Top, Bottom, TopBottom, All, Sides, None } +#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone)] +pub enum TableAlignH { +    Left, +    Right, +    Center, +    Justify, +    Char, +} +#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone)] +pub enum TableBorder { +    Top, +    Bottom, +    TopBottom, +    All, +    Sides, +    None, +} -#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub struct ID(pub String); -#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub struct NameToken(pub String); +#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone)] +pub struct ID(pub String); +#[derive(Debug, PartialEq, Eq, Hash, Serialize, Clone)] +pub struct NameToken(pub String);  // The table DTD has the cols attribute of tgroup as required, but having  // TableGroupCols not implement Default would leave no possible implementation  // for TableGroup::with_children. -#[derive(Debug,PartialEq,Eq,Hash,Serialize,Clone)] pub struct TableGroupCols(pub usize); -impl Default for TableGroupCols { -	fn default() -> Self { -		TableGroupCols(0) -	} -} +#[derive(Default, Debug, PartialEq, Eq, Hash, Serialize, Clone)] +pub struct TableGroupCols(pub usize);  // no eq for f64 -#[derive(Debug,PartialEq,Serialize,Clone)] -pub enum Measure {  // http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#length-units -	Em(f64), -	Ex(f64), -	Mm(f64), -	Cm(f64), -	In(f64), -	Px(f64), -	Pt(f64), -	Pc(f64), +#[derive(Debug, PartialEq, Serialize, Clone)] +pub enum Measure { +    // http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#length-units +    Em(f64), +    Ex(f64), +    Mm(f64), +    Cm(f64), +    In(f64), +    Px(f64), +    Pt(f64), +    Pc(f64),  }  impl FromStr for AlignHV { -	type Err = Error; -	fn from_str(s: &str) -> Result<Self, Self::Err> { -		use self::AlignHV::*; -		Ok(match s { -			"top"    => Top, -			"middle" => Middle, -			"bottom" => Bottom, -			"left"   => Left, -			"center" => Center, -			"right"  => Right, -			s => bail!("Invalid Alignment {}", s), -		}) -	} +    type Err = Error; +    fn from_str(s: &str) -> Result<Self, Self::Err> { +        use self::AlignHV::*; +        Ok(match s { +            "top" => Top, +            "middle" => Middle, +            "bottom" => Bottom, +            "left" => Left, +            "center" => Center, +            "right" => Right, +            s => bail!("Invalid Alignment {}", s), +        }) +    }  }  impl From<&str> for ID { -	fn from(s: &str) -> Self { -		ID(s.to_owned().replace(' ', "-")) -	} +    fn from(s: &str) -> Self { +        ID(s.to_owned().replace(' ', "-")) +    }  }  impl From<&str> for NameToken { -	fn from(s: &str) -> Self { -		NameToken(s.to_owned()) -	} +    fn from(s: &str) -> Self { +        NameToken(s.to_owned()) +    }  }  impl FromStr for Measure { -	type Err = Error; -	fn from_str(s: &str) -> Result<Self, Self::Err> { -		use self::Measure::*; -		let re = Regex::new(r"(?P<float>\d+\.\d*|\.?\d+)\s*(?P<unit>em|ex|mm|cm|in|px|pt|pc)").unwrap(); -		let caps: regex::Captures = re.captures(s).ok_or_else(|| format_err!("Invalid measure"))?; -		let value: f64 = caps["float"].parse()?; -		Ok(match &caps["unit"] { -			"em" => Em(value), -			"ex" => Ex(value), -			"mm" => Mm(value), -			"cm" => Cm(value), -			"in" => In(value), -			"px" => Px(value), -			"pt" => Pt(value), -			"pc" => Pc(value), -			_ => unreachable!(), -		}) -	} +    type Err = Error; +    fn from_str(s: &str) -> Result<Self, Self::Err> { +        use self::Measure::*; +        let re = +            Regex::new(r"(?P<float>\d+\.\d*|\.?\d+)\s*(?P<unit>em|ex|mm|cm|in|px|pt|pc)").unwrap(); +        let caps: regex::Captures = re +            .captures(s) +            .ok_or_else(|| format_err!("Invalid measure"))?; +        let value: f64 = caps["float"].parse()?; +        Ok(match &caps["unit"] { +            "em" => Em(value), +            "ex" => Ex(value), +            "mm" => Mm(value), +            "cm" => Cm(value), +            "in" => In(value), +            "px" => Px(value), +            "pt" => Pt(value), +            "pc" => Pc(value), +            _ => unreachable!(), +        }) +    }  }  #[cfg(test)]  mod parse_tests { -	use super::*; -	 -	#[test] -	fn measure() { -		let _a: Measure = "1.5em".parse().unwrap(); -		let _b: Measure = "20 mm".parse().unwrap(); -		let _c: Measure = ".5in".parse().unwrap(); -		let _d: Measure = "1.pc".parse().unwrap(); -	} +    use super::*; + +    #[test] +    fn measure() { +        let _a: Measure = "1.5em".parse().unwrap(); +        let _b: Measure = "20 mm".parse().unwrap(); +        let _c: Measure = ".5in".parse().unwrap(); +        let _d: Measure = "1.pc".parse().unwrap(); +    }  }  pub(crate) trait CanBeEmpty { -	fn is_empty(&self) -> bool; +    fn is_empty(&self) -> bool;  }  /* Specialization necessary  impl<T> CanBeEmpty for T { -	fn is_empty(&self) -> bool { false } +    fn is_empty(&self) -> bool { false }  }  */  macro_rules! impl_cannot_be_empty { -	($t:ty) => { -		impl CanBeEmpty for $t { -			fn is_empty(&self) -> bool { false } -		} -	}; -	($t:ty, $($ts:ty),*) => { -		impl_cannot_be_empty!($t); -		impl_cannot_be_empty!($($ts),*); -	}; +    ($t:ty) => { +        impl CanBeEmpty for $t { +            fn is_empty(&self) -> bool { false } +        } +    }; +    ($t:ty, $($ts:ty),*) => { +        impl_cannot_be_empty!($t); +        impl_cannot_be_empty!($($ts),*); +    };  }  impl_cannot_be_empty!(Url);  impl_cannot_be_empty!(TableGroupCols);  impl<T> CanBeEmpty for Option<T> { -	fn is_empty(&self) -> bool { self.is_none() } +    fn is_empty(&self) -> bool { +        self.is_none() +    }  }  impl<T> CanBeEmpty for Vec<T> { -	fn is_empty(&self) -> bool { self.is_empty() } +    fn is_empty(&self) -> bool { +        self.is_empty() +    }  }  impl CanBeEmpty for bool { -	fn is_empty(&self) -> bool { !self } +    fn is_empty(&self) -> bool { +        !self +    }  }  impl CanBeEmpty for FixedSpace { -	fn is_empty(&self) -> bool { self == &FixedSpace::default() } +    fn is_empty(&self) -> bool { +        self == &FixedSpace::default() +    }  } - diff --git a/document_tree/src/element_categories.rs b/document_tree/src/element_categories.rs index 24a0798..e0a1886 100644 --- a/document_tree/src/element_categories.rs +++ b/document_tree/src/element_categories.rs @@ -1,130 +1,200 @@ -use std::fmt::{self,Debug,Formatter}; +use std::fmt::{self, Debug, Formatter};  use serde_derive::Serialize;  use crate::elements::*;  pub trait HasChildren<C> { -	fn with_children(children: Vec<C>) -> Self; -	fn children(&self) -> &Vec<C>; -	fn children_mut(&mut self) -> &mut Vec<C>; -	fn append_child<R: Into<C>>(&mut self, child: R) { -		self.children_mut().push(child.into()); -	} -	fn append_children<R: Into<C> + Clone>(&mut self, more: &[R]) { -		let children = self.children_mut(); -		children.reserve(more.len()); -		for child in more { -			children.push(child.clone().into()); -		} -	} +    fn with_children(children: Vec<C>) -> Self; +    fn children(&self) -> &Vec<C>; +    fn children_mut(&mut self) -> &mut Vec<C>; +    fn append_child<R: Into<C>>(&mut self, child: R) { +        self.children_mut().push(child.into()); +    } +    fn append_children<R: Into<C> + Clone>(&mut self, more: &[R]) { +        let children = self.children_mut(); +        children.reserve(more.len()); +        for child in more { +            children.push(child.clone().into()); +        } +    }  }  macro_rules! impl_into { -	([ $( (($subcat:ident :: $entry:ident), $supcat:ident), )+ ]) => { -		$( impl_into!($subcat::$entry => $supcat); )+ -	}; -	($subcat:ident :: $entry:ident => $supcat:ident ) => { -		impl Into<$supcat> for $entry { -			fn into(self) -> $supcat { -				$supcat::$subcat(Box::new(self.into())) -			} -		} -	}; +    ([ $( (($subcat:ident :: $entry:ident), $supcat:ident), )+ ]) => { +        $( impl_into!($subcat::$entry => $supcat); )+ +    }; +    ($subcat:ident :: $entry:ident => $supcat:ident ) => { +        impl From<$entry> for $supcat { +            fn from(inner: $entry) -> Self { +                $supcat::$subcat(Box::new(inner.into())) +            } +        } +    };  }  macro_rules! synonymous_enum { -	( $subcat:ident : $($supcat:ident),+ ; $midcat:ident : $supsupcat:ident { $($entry:ident),+ $(,)* } ) => { -		synonymous_enum!($subcat : $( $supcat ),+ , $midcat { $($entry,)* }); -		$( impl_into!($midcat::$entry => $supsupcat); )+ -	}; -	( $subcat:ident : $($supcat:ident),+ { $($entry:ident),+ $(,)* } ) => { -		synonymous_enum!($subcat { $( $entry, )* }); -		cartesian!(impl_into, [ $( ($subcat::$entry) ),+ ], [ $($supcat),+ ]); -	}; -	( $name:ident { $( $entry:ident ),+ $(,)* } ) => { -		#[derive(PartialEq,Serialize,Clone)] -		pub enum $name { $( -			$entry(Box<$entry>), -		)* } -		 -		impl Debug for $name { -			fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> { -				match *self { -					$( $name::$entry(ref inner) => inner.fmt(fmt), )* -				} -			} -		} -		 -		$( impl Into<$name> for $entry { -			fn into(self) -> $name { -				$name::$entry(Box::new(self)) -			} -		} )* -	}; +    ( $subcat:ident : $($supcat:ident),+ ; $midcat:ident : $supsupcat:ident { $($entry:ident),+ $(,)* } ) => { +        synonymous_enum!($subcat : $( $supcat ),+ , $midcat { $($entry,)* }); +        $( impl_into!($midcat::$entry => $supsupcat); )+ +    }; +    ( $subcat:ident : $($supcat:ident),+ { $($entry:ident),+ $(,)* } ) => { +        synonymous_enum!($subcat { $( $entry, )* }); +        cartesian!(impl_into, [ $( ($subcat::$entry) ),+ ], [ $($supcat),+ ]); +    }; +    ( $name:ident { $( $entry:ident ),+ $(,)* } ) => { +        #[derive(PartialEq,Serialize,Clone)] +        pub enum $name { $( +            $entry(Box<$entry>), +        )* } + +        impl Debug for $name { +            fn fmt(&self, fmt: &mut Formatter) -> Result<(), fmt::Error> { +                match *self { +                    $( $name::$entry(ref inner) => inner.fmt(fmt), )* +                } +            } +        } + +        $( impl From<$entry> for $name { +            fn from(inner: $entry) -> Self { +                $name::$entry(Box::new(inner)) +            } +        } )* +    };  } -synonymous_enum!(StructuralSubElement { Title, Subtitle, Decoration, Docinfo, SubStructure }); +synonymous_enum!(StructuralSubElement { +    Title, +    Subtitle, +    Decoration, +    Docinfo, +    SubStructure +});  synonymous_enum!(SubStructure: StructuralSubElement { Topic, Sidebar, Transition, Section, BodyElement });  synonymous_enum!(BodyElement: SubTopic, SubSidebar, SubBlockQuote, SubFootnote, SubFigure; SubStructure: StructuralSubElement { -	//Simple -	Paragraph, LiteralBlock, DoctestBlock, MathBlock, Rubric, SubstitutionDefinition, Comment, Pending, Target, Raw, Image, -	//Compound -	Compound, Container, -	BulletList, EnumeratedList, DefinitionList, FieldList, OptionList, -	LineBlock, BlockQuote, Admonition, Attention, Hint, Note, Caution, Danger, Error, Important, Tip, Warning, Footnote, Citation, SystemMessage, Figure, Table +    //Simple +    Paragraph, LiteralBlock, DoctestBlock, MathBlock, Rubric, SubstitutionDefinition, Comment, Pending, Target, Raw, Image, +    //Compound +    Compound, Container, +    BulletList, EnumeratedList, DefinitionList, FieldList, OptionList, +    LineBlock, BlockQuote, Admonition, Attention, Hint, Note, Caution, Danger, Error, Important, Tip, Warning, Footnote, Citation, SystemMessage, Figure, Table  }); -synonymous_enum!(BibliographicElement { Author, Authors, Organization, Address, Contact, Version, Revision, Status, Date, Copyright, Field }); +synonymous_enum!(BibliographicElement { +    Author, +    Authors, +    Organization, +    Address, +    Contact, +    Version, +    Revision, +    Status, +    Date, +    Copyright, +    Field +});  synonymous_enum!(TextOrInlineElement { -	String, Emphasis, Strong, Literal, Reference, FootnoteReference, CitationReference, SubstitutionReference, TitleReference, Abbreviation, Acronym, Superscript, Subscript, Inline, Problematic, Generated, Math, -	//also have non-inline versions. Inline image is no figure child, inline target has content -	TargetInline, RawInline, ImageInline +    String, +    Emphasis, +    Strong, +    Literal, +    Reference, +    FootnoteReference, +    CitationReference, +    SubstitutionReference, +    TitleReference, +    Abbreviation, +    Acronym, +    Superscript, +    Subscript, +    Inline, +    Problematic, +    Generated, +    Math, +    //also have non-inline versions. Inline image is no figure child, inline target has content +    TargetInline, +    RawInline, +    ImageInline  });  //--------------\\  //Content Models\\  //--------------\\ -synonymous_enum!(AuthorInfo { Author, Organization, Address, Contact }); +synonymous_enum!(AuthorInfo { +    Author, +    Organization, +    Address, +    Contact +});  synonymous_enum!(DecorationElement { Header, Footer });  synonymous_enum!(SubTopic { Title, BodyElement }); -synonymous_enum!(SubSidebar { Topic, Title, Subtitle, BodyElement }); -synonymous_enum!(SubDLItem { Term, Classifier, Definition }); -synonymous_enum!(SubField { FieldName, FieldBody }); -synonymous_enum!(SubOptionListItem { OptionGroup, Description }); -synonymous_enum!(SubOption { OptionString, OptionArgument }); +synonymous_enum!(SubSidebar { +    Topic, +    Title, +    Subtitle, +    BodyElement +}); +synonymous_enum!(SubDLItem { +    Term, +    Classifier, +    Definition +}); +synonymous_enum!(SubField { +    FieldName, +    FieldBody +}); +synonymous_enum!(SubOptionListItem { +    OptionGroup, +    Description +}); +synonymous_enum!(SubOption { +    OptionString, +    OptionArgument +});  synonymous_enum!(SubLineBlock { LineBlock, Line }); -synonymous_enum!(SubBlockQuote { Attribution, BodyElement }); +synonymous_enum!(SubBlockQuote { +    Attribution, +    BodyElement +});  synonymous_enum!(SubFootnote { Label, BodyElement }); -synonymous_enum!(SubFigure { Caption, Legend, BodyElement }); +synonymous_enum!(SubFigure { +    Caption, +    Legend, +    BodyElement +});  synonymous_enum!(SubTable { Title, TableGroup }); -synonymous_enum!(SubTableGroup { TableColspec, TableHead, TableBody }); +synonymous_enum!(SubTableGroup { +    TableColspec, +    TableHead, +    TableBody +});  #[cfg(test)]  mod conversion_tests { -	use std::default::Default; -	use super::*; -	 -	#[test] -	fn basic() { -		let _: BodyElement = Paragraph::default().into(); -	} -	 -	#[test] -	fn more() { -		let _: SubStructure = Paragraph::default().into(); -	} -	 -	#[test] -	fn even_more() { -		let _: StructuralSubElement = Paragraph::default().into(); -	} -	 -	#[test] -	fn super_() { -		let be: BodyElement = Paragraph::default().into(); -		let _: StructuralSubElement = be.into(); -	} +    use super::*; +    use std::default::Default; + +    #[test] +    fn basic() { +        let _: BodyElement = Paragraph::default().into(); +    } + +    #[test] +    fn more() { +        let _: SubStructure = Paragraph::default().into(); +    } + +    #[test] +    fn even_more() { +        let _: StructuralSubElement = Paragraph::default().into(); +    } + +    #[test] +    fn super_() { +        let be: BodyElement = Paragraph::default().into(); +        let _: StructuralSubElement = be.into(); +    }  } diff --git a/document_tree/src/element_types.rs b/document_tree/src/element_types.rs index 429573e..42571d1 100644 --- a/document_tree/src/element_types.rs +++ b/document_tree/src/element_types.rs @@ -1,96 +1,96 @@  // enum ElementType { -// 	//structual elements -// 	Section, Topic, Sidebar, -// -// 	//structural subelements -// 	Title, Subtitle, Decoration, Docinfo, Transition, -// -// 	//bibliographic elements -// 	Author, Authors, Organization, -// 	Address { space: FixedSpace }, -// 	Contact, Version, Revision, Status, -// 	Date, Copyright, Field, -// -// 	//decoration elements -// 	Header, Footer, -// -// 	//simple body elements -// 	Paragraph, -// 	LiteralBlock { space: FixedSpace }, -// 	DoctestBlock { space: FixedSpace }, -// 	MathBlock, Rubric, -// 	SubstitutionDefinition { ltrim: bool, rtrim: bool }, -// 	Comment { space: FixedSpace }, -// 	Pending, -// 	Target { refuri: Url, refid: ID, refname: Vec<NameToken>, anonymous: bool }, -// 	Raw { space: FixedSpace, format: Vec<NameToken> }, -// 	Image { -// 		align: AlignHV, -// 		uri: Url, -// 		alt: String, -// 		height: Measure, -// 		width: Measure, -// 		scale: f64, -// 	}, -// -// 	//compound body elements -// 	Compound, Container, -// -// 	BulletList { bullet: String }, -// 	EnumeratedList { enumtype: EnumeratedListType, prefix: String, suffix: String }, -// 	DefinitionList, FieldList, OptionList, -// -// 	LineBlock, BlockQuote, -// 	Admonition, Attention, Hint, Note, -// 	Caution, Danger, Error, Important, -// 	Tip, Warning, -// 	Footnote { backrefs: Vec<ID>, auto: bool }, -// 	Citation { backrefs: Vec<ID> }, -// 	SystemMessage { backrefs: Vec<ID>, level: usize, line: usize, type_: NameToken }, -// 	Figure { align: AlignH, width: usize }, -// 	Table, //TODO: Table -// -// 	//body sub elements -// 	ListItem, -// -// 	DefinitionListItem, Term, -// 	Classifier, Definition, -// -// 	FieldName, FieldBody, -// -// 	OptionListItem, OptionGroup, Description, Option_, OptionString, -// 	OptionArgument { delimiter: String }, -// -// 	Line, Attribution, Label, -// -// 	Caption, Legend, -// -// 	//inline elements -// 	Emphasis, Strong, Literal, -// 	Reference { name: String, refuri: Url, refid: ID, refname: Vec<NameToken> }, -// 	FootnoteReference { refid: ID, refname: Vec<NameToken>, auto: bool }, -// 	CitationReference { refid: ID, refname: Vec<NameToken> }, -// 	SubstitutionReference { refname: Vec<NameToken> }, -// 	TitleReference, -// 	Abbreviation, Acronym, -// 	Superscript, Subscript, -// 	Inline, -// 	Problematic { refid: ID }, -// 	Generated, Math, -// -// 	//also have non-inline versions. Inline image is no figure child, inline target has content -// 	TargetInline { refuri: Url, refid: ID, refname: Vec<NameToken>, anonymous: bool }, -// 	RawInline { space: FixedSpace, format: Vec<NameToken> }, -// 	ImageInline { -// 		align: AlignHV, -// 		uri: Url, -// 		alt: String, -// 		height: Measure, -// 		width: Measure, -// 		scale: f64, -// 	}, -// -// 	//text element -// 	TextElement, +//     //structual elements +//     Section, Topic, Sidebar, +// +//     //structural subelements +//     Title, Subtitle, Decoration, Docinfo, Transition, +// +//     //bibliographic elements +//     Author, Authors, Organization, +//     Address { space: FixedSpace }, +//     Contact, Version, Revision, Status, +//     Date, Copyright, Field, +// +//     //decoration elements +//     Header, Footer, +// +//     //simple body elements +//     Paragraph, +//     LiteralBlock { space: FixedSpace }, +//     DoctestBlock { space: FixedSpace }, +//     MathBlock, Rubric, +//     SubstitutionDefinition { ltrim: bool, rtrim: bool }, +//     Comment { space: FixedSpace }, +//     Pending, +//     Target { refuri: Url, refid: ID, refname: Vec<NameToken>, anonymous: bool }, +//     Raw { space: FixedSpace, format: Vec<NameToken> }, +//     Image { +//         align: AlignHV, +//         uri: Url, +//         alt: String, +//         height: Measure, +//         width: Measure, +//         scale: f64, +//     }, +// +//     //compound body elements +//     Compound, Container, +// +//     BulletList { bullet: String }, +//     EnumeratedList { enumtype: EnumeratedListType, prefix: String, suffix: String }, +//     DefinitionList, FieldList, OptionList, +// +//     LineBlock, BlockQuote, +//     Admonition, Attention, Hint, Note, +//     Caution, Danger, Error, Important, +//     Tip, Warning, +//     Footnote { backrefs: Vec<ID>, auto: bool }, +//     Citation { backrefs: Vec<ID> }, +//     SystemMessage { backrefs: Vec<ID>, level: usize, line: usize, type_: NameToken }, +//     Figure { align: AlignH, width: usize }, +//     Table, //TODO: Table +// +//     //body sub elements +//     ListItem, +// +//     DefinitionListItem, Term, +//     Classifier, Definition, +// +//     FieldName, FieldBody, +// +//     OptionListItem, OptionGroup, Description, Option_, OptionString, +//     OptionArgument { delimiter: String }, +// +//     Line, Attribution, Label, +// +//     Caption, Legend, +// +//     //inline elements +//     Emphasis, Strong, Literal, +//     Reference { name: String, refuri: Url, refid: ID, refname: Vec<NameToken> }, +//     FootnoteReference { refid: ID, refname: Vec<NameToken>, auto: bool }, +//     CitationReference { refid: ID, refname: Vec<NameToken> }, +//     SubstitutionReference { refname: Vec<NameToken> }, +//     TitleReference, +//     Abbreviation, Acronym, +//     Superscript, Subscript, +//     Inline, +//     Problematic { refid: ID }, +//     Generated, Math, +// +//     //also have non-inline versions. Inline image is no figure child, inline target has content +//     TargetInline { refuri: Url, refid: ID, refname: Vec<NameToken>, anonymous: bool }, +//     RawInline { space: FixedSpace, format: Vec<NameToken> }, +//     ImageInline { +//         align: AlignHV, +//         uri: Url, +//         alt: String, +//         height: Measure, +//         width: Measure, +//         scale: f64, +//     }, +// +//     //text element +//     TextElement,  // } diff --git a/document_tree/src/elements.rs b/document_tree/src/elements.rs index 1db0a24..4921e1a 100644 --- a/document_tree/src/elements.rs +++ b/document_tree/src/elements.rs @@ -1,288 +1,348 @@ -use std::path::PathBuf;  use serde_derive::Serialize; +use std::path::PathBuf; -use crate::attribute_types::{CanBeEmpty,ID,NameToken}; -use crate::extra_attributes::{self,ExtraAttributes}; +use crate::attribute_types::{CanBeEmpty, NameToken, ID};  use crate::element_categories::*; - +use crate::extra_attributes::{self, ExtraAttributes};  //-----------------\\  //Element hierarchy\\  //-----------------\\  pub trait Element { -	/// A list containing one or more unique identifier keys -	fn     ids    (&    self) -> &    Vec<ID>; -	fn     ids_mut(&mut self) -> &mut Vec<ID>; -	/// a list containing the names of an element, typically originating from the element's title or content. -	/// Each name in names must be unique; if there are name conflicts (two or more elements want to the same name), -	/// the contents will be transferred to the dupnames attribute on the duplicate elements. -	/// An element may have at most one of the names or dupnames attributes, but not both. -	fn   names    (&    self) -> &    Vec<NameToken>; -	fn   names_mut(&mut self) -> &mut Vec<NameToken>; -	fn  source    (&    self) -> &    Option<PathBuf>; -	fn  source_mut(&mut self) -> &mut Option<PathBuf>; -	fn classes    (&    self) -> &    Vec<String>; -	fn classes_mut(&mut self) -> &mut Vec<String>; +    /// A list containing one or more unique identifier keys +    fn ids(&self) -> &Vec<ID>; +    fn ids_mut(&mut self) -> &mut Vec<ID>; +    /// a list containing the names of an element, typically originating from the element's title or content. +    /// Each name in names must be unique; if there are name conflicts (two or more elements want to the same name), +    /// the contents will be transferred to the dupnames attribute on the duplicate elements. +    /// An element may have at most one of the names or dupnames attributes, but not both. +    fn names(&self) -> &Vec<NameToken>; +    fn names_mut(&mut self) -> &mut Vec<NameToken>; +    fn source(&self) -> &Option<PathBuf>; +    fn source_mut(&mut self) -> &mut Option<PathBuf>; +    fn classes(&self) -> &Vec<String>; +    fn classes_mut(&mut self) -> &mut Vec<String>;  } -#[derive(Debug,Default,PartialEq,Serialize,Clone)] +#[derive(Debug, Default, PartialEq, Serialize, Clone)]  pub struct CommonAttributes { -	#[serde(skip_serializing_if = "CanBeEmpty::is_empty")] -	ids: Vec<ID>, -	#[serde(skip_serializing_if = "CanBeEmpty::is_empty")] -	names: Vec<NameToken>, -	#[serde(skip_serializing_if = "CanBeEmpty::is_empty")] -	source: Option<PathBuf>, -	#[serde(skip_serializing_if = "CanBeEmpty::is_empty")] -	classes: Vec<String>, -	//TODO: dupnames +    #[serde(skip_serializing_if = "CanBeEmpty::is_empty")] +    ids: Vec<ID>, +    #[serde(skip_serializing_if = "CanBeEmpty::is_empty")] +    names: Vec<NameToken>, +    #[serde(skip_serializing_if = "CanBeEmpty::is_empty")] +    source: Option<PathBuf>, +    #[serde(skip_serializing_if = "CanBeEmpty::is_empty")] +    classes: Vec<String>, +    //TODO: dupnames  }  //----\\  //impl\\  //----\\ -macro_rules! impl_element { ($name:ident) => ( -	impl Element for $name { -		fn     ids    (&    self) -> &    Vec<ID>         { &    self.common.ids     } -		fn     ids_mut(&mut self) -> &mut Vec<ID>         { &mut self.common.ids     } -		fn   names    (&    self) -> &    Vec<NameToken>  { &    self.common.names   } -		fn   names_mut(&mut self) -> &mut Vec<NameToken>  { &mut self.common.names   } -		fn  source    (&    self) -> &    Option<PathBuf> { &    self.common.source  } -		fn  source_mut(&mut self) -> &mut Option<PathBuf> { &mut self.common.source  } -		fn classes    (&    self) -> &    Vec<String> { &    self.common.classes } -		fn classes_mut(&mut self) -> &mut Vec<String> { &mut self.common.classes } -	} -)} +macro_rules! impl_element { +    ($name:ident) => { +        impl Element for $name { +            fn ids(&self) -> &Vec<ID> { +                &self.common.ids +            } +            fn ids_mut(&mut self) -> &mut Vec<ID> { +                &mut self.common.ids +            } +            fn names(&self) -> &Vec<NameToken> { +                &self.common.names +            } +            fn names_mut(&mut self) -> &mut Vec<NameToken> { +                &mut self.common.names +            } +            fn source(&self) -> &Option<PathBuf> { +                &self.common.source +            } +            fn source_mut(&mut self) -> &mut Option<PathBuf> { +                &mut self.common.source +            } +            fn classes(&self) -> &Vec<String> { +                &self.common.classes +            } +            fn classes_mut(&mut self) -> &mut Vec<String> { +                &mut self.common.classes +            } +        } +    }; +} -macro_rules! impl_children { ($name:ident, $childtype:ident) => ( -	impl HasChildren<$childtype> for $name { -		#[allow(clippy::needless_update)] -		fn with_children(children: Vec<$childtype>) -> $name { $name { children: children, ..Default::default() } } -		fn children    (&    self) -> &    Vec<$childtype> { &    self.children } -		fn children_mut(&mut self) -> &mut Vec<$childtype> { &mut self.children } -	} -)} +macro_rules! impl_children { +    ($name:ident, $childtype:ident) => { +        impl HasChildren<$childtype> for $name { +            #[allow(clippy::needless_update)] +            fn with_children(children: Vec<$childtype>) -> $name { +                $name { +                    children, +                    ..Default::default() +                } +            } +            fn children(&self) -> &Vec<$childtype> { +                &self.children +            } +            fn children_mut(&mut self) -> &mut Vec<$childtype> { +                &mut self.children +            } +        } +    }; +}  macro_rules! impl_extra { ($name:ident $($more:tt)*) => ( -	impl ExtraAttributes<extra_attributes::$name> for $name { -		#[allow(clippy::needless_update)] -		fn with_extra(extra: extra_attributes::$name) -> $name { $name { common: Default::default(), extra: extra $($more)* } } -		fn extra    (&    self) -> &    extra_attributes::$name { &    self.extra } -		fn extra_mut(&mut self) -> &mut extra_attributes::$name { &mut self.extra } -	} +    impl ExtraAttributes<extra_attributes::$name> for $name { +        #[allow(clippy::needless_update)] +        fn with_extra(extra: extra_attributes::$name) -> $name { $name { common: Default::default(), extra $($more)* } } +        fn extra    (&    self) -> &    extra_attributes::$name { &    self.extra } +        fn extra_mut(&mut self) -> &mut extra_attributes::$name { &mut self.extra } +    }  )}  trait HasExtraAndChildren<C, A> { -	fn with_extra_and_children(extra: A, children: Vec<C>) -> Self; +    fn with_extra_and_children(extra: A, children: Vec<C>) -> Self;  } -impl<T, C, A> HasExtraAndChildren<C, A> for T where T: HasChildren<C> + ExtraAttributes<A> { -	#[allow(clippy::needless_update)] -	fn with_extra_and_children(extra: A, mut children: Vec<C>) -> Self { -		let mut r = Self::with_extra(extra); -		r.children_mut().extend(children.drain(..)); -		r -	} +impl<T, C, A> HasExtraAndChildren<C, A> for T +where +    T: HasChildren<C> + ExtraAttributes<A>, +{ +    #[allow(clippy::needless_update)] +    fn with_extra_and_children(extra: A, mut children: Vec<C>) -> Self { +        let mut r = Self::with_extra(extra); +        r.children_mut().append(&mut children); +        r +    }  }  macro_rules! impl_new {( -	$(#[$attr:meta])* -	pub struct $name:ident { $( -		$(#[$fattr:meta])* -		$field:ident : $typ:path -	),* $(,)* } +    $(#[$attr:meta])* +    pub struct $name:ident { $( +        $(#[$fattr:meta])* +        $field:ident : $typ:path +    ),* $(,)* }  ) => ( -	$(#[$attr])* -	#[derive(Debug,PartialEq,Serialize,Clone)] -	pub struct $name { $(  -		$(#[$fattr])* $field: $typ, -	)* } -	impl $name { -		pub fn new( $( $field: $typ, )* ) -> $name { $name { $( $field: $field, )* } } -	} +    $(#[$attr])* +    #[derive(Debug,PartialEq,Serialize,Clone)] +    pub struct $name { $( +        $(#[$fattr])* $field: $typ, +    )* } +    impl $name { +        pub fn new( $( $field: $typ, )* ) -> $name { $name { $( $field, )* } } +    }  )}  macro_rules! impl_elem { -	($name:ident) => { -		impl_new!(#[derive(Default)] pub struct $name { -			#[serde(flatten)] common: CommonAttributes, -		}); -		impl_element!($name); -	}; -	($name:ident; +) => { -		impl_new!(#[derive(Default)] pub struct $name { -			#[serde(flatten)] common: CommonAttributes, -			#[serde(flatten)] extra: extra_attributes::$name, -		}); -		impl_element!($name); impl_extra!($name, ..Default::default()); -	}; -	($name:ident; *) => { //same as above with no default -		impl_new!(pub struct $name { -			#[serde(flatten)] common: CommonAttributes, -			#[serde(flatten)] extra: extra_attributes::$name -		}); -		impl_element!($name); impl_extra!($name); -	}; -	($name:ident, $childtype:ident) => { -		impl_new!(#[derive(Default)] pub struct $name { -			#[serde(flatten)] common: CommonAttributes, -			children: Vec<$childtype>, -		}); -		impl_element!($name); impl_children!($name, $childtype); -	}; -	($name:ident, $childtype:ident; +) => { -		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, ..Default::default()); impl_children!($name, $childtype); -	}; +    ($name:ident) => { +        impl_new!( +            #[derive(Default)] +            pub struct $name { +                #[serde(flatten)] +                common: CommonAttributes, +            } +        ); +        impl_element!($name); +    }; +    ($name:ident; +) => { +        impl_new!( +            #[derive(Default)] +            pub struct $name { +                #[serde(flatten)] +                common: CommonAttributes, +                #[serde(flatten)] +                extra: extra_attributes::$name, +            } +        ); +        impl_element!($name); +        impl_extra!($name, ..Default::default()); +    }; +    ($name:ident; *) => { +        //same as above with no default +        impl_new!( +            pub struct $name { +                #[serde(flatten)] +                common: CommonAttributes, +                #[serde(flatten)] +                extra: extra_attributes::$name, +            } +        ); +        impl_element!($name); +        impl_extra!($name); +    }; +    ($name:ident, $childtype:ident) => { +        impl_new!( +            #[derive(Default)] +            pub struct $name { +                #[serde(flatten)] +                common: CommonAttributes, +                children: Vec<$childtype>, +            } +        ); +        impl_element!($name); +        impl_children!($name, $childtype); +    }; +    ($name:ident, $childtype:ident; +) => { +        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, ..Default::default()); +        impl_children!($name, $childtype); +    };  }  macro_rules! impl_elems { ( $( ($($args:tt)*) )* ) => ( -	$( impl_elem!($($args)*); )* +    $( impl_elem!($($args)*); )*  )} - -#[derive(Default,Debug,Serialize)] -pub struct Document { children: Vec<StructuralSubElement> } +#[derive(Default, Debug, Serialize)] +pub struct Document { +    children: Vec<StructuralSubElement>, +}  impl_children!(Document, StructuralSubElement);  impl_elems!( -	//structual elements -	(Section, StructuralSubElement) -	(Topic,   SubTopic) -	(Sidebar, SubSidebar) -	 -	//structural subelements -	(Title,      TextOrInlineElement) -	(Subtitle,   TextOrInlineElement) -	(Decoration, DecorationElement) -	(Docinfo,    BibliographicElement) -	(Transition) -	 -	//bibliographic elements -	(Author,       TextOrInlineElement) -	(Authors,      AuthorInfo) -	(Organization, TextOrInlineElement) -	(Address,      TextOrInlineElement; +) -	(Contact,      TextOrInlineElement) -	(Version,      TextOrInlineElement) -	(Revision,     TextOrInlineElement) -	(Status,       TextOrInlineElement) -	(Date,         TextOrInlineElement) -	(Copyright,    TextOrInlineElement) -	(Field,        SubField) -	 -	//decoration elements -	(Header, BodyElement) -	(Footer, BodyElement) -	 -	//simple body elements -	(Paragraph,              TextOrInlineElement) -	(LiteralBlock,           TextOrInlineElement; +) -	(DoctestBlock,           TextOrInlineElement; +) -	(MathBlock,              String) -	(Rubric,                 TextOrInlineElement) -	(SubstitutionDefinition, TextOrInlineElement; +) -	(Comment,                TextOrInlineElement; +) -	(Pending) -	(Target; +) -	(Raw, String; +) -	(Image; *) -	 -	//compound body elements -	(Compound,  BodyElement) -	(Container, BodyElement) -	 -	(BulletList,     ListItem; +) -	(EnumeratedList, ListItem; +) -	(DefinitionList, DefinitionListItem) -	(FieldList,      Field) -	(OptionList,     OptionListItem) -	 -	(LineBlock,     SubLineBlock) -	(BlockQuote,    SubBlockQuote) -	(Admonition,    SubTopic) -	(Attention,     BodyElement) -	(Hint,          BodyElement) -	(Note,          BodyElement) -	(Caution,       BodyElement) -	(Danger,        BodyElement) -	(Error,         BodyElement) -	(Important,     BodyElement) -	(Tip,           BodyElement) -	(Warning,       BodyElement) -	(Footnote,      SubFootnote; +) -	(Citation,      SubFootnote; +) -	(SystemMessage, BodyElement; +) -	(Figure,        SubFigure;   +) -	(Table,         SubTable;    +) - -	//table elements -	(TableGroup, SubTableGroup; +) -	(TableHead,  TableRow;      +) -	(TableBody,  TableRow;      +) -	(TableRow,   TableEntry;    +) -	(TableEntry, BodyElement;   +) -	(TableColspec; +) -	 -	//body sub elements -	(ListItem, BodyElement) -	 -	(DefinitionListItem, SubDLItem) -	(Term,               TextOrInlineElement) -	(Classifier,         TextOrInlineElement) -	(Definition,         BodyElement) -	 -	(FieldName, TextOrInlineElement) -	(FieldBody, BodyElement) -	 -	(OptionListItem, SubOptionListItem) -	(OptionGroup,    Option_) -	(Description,    BodyElement) -	(Option_,        SubOption) -	(OptionString,   String) -	(OptionArgument, String; +) -	 -	(Line,        TextOrInlineElement) -	(Attribution, TextOrInlineElement) -	(Label,       TextOrInlineElement) -	 -	(Caption, TextOrInlineElement) -	(Legend,  BodyElement) -	 -	//inline elements -	(Emphasis,              TextOrInlineElement) -	(Literal,               String) -	(Reference,             TextOrInlineElement; +) -	(Strong,                TextOrInlineElement) -	(FootnoteReference,     TextOrInlineElement; +) -	(CitationReference,     TextOrInlineElement; +) -	(SubstitutionReference, TextOrInlineElement; +) -	(TitleReference,        TextOrInlineElement) -	(Abbreviation,          TextOrInlineElement) -	(Acronym,               TextOrInlineElement) -	(Superscript,           TextOrInlineElement) -	(Subscript,             TextOrInlineElement) -	(Inline,                TextOrInlineElement) -	(Problematic,           TextOrInlineElement; +) -	(Generated,             TextOrInlineElement) -	(Math,                  String) -	 -	//also have non-inline versions. Inline image is no figure child, inline target has content -	(TargetInline, String; +) -	(RawInline,    String; +) -	(ImageInline; *) -	 -	//text element = String +    //structual elements +    (Section, StructuralSubElement) +    (Topic,   SubTopic) +    (Sidebar, SubSidebar) + +    //structural subelements +    (Title,      TextOrInlineElement) +    (Subtitle,   TextOrInlineElement) +    (Decoration, DecorationElement) +    (Docinfo,    BibliographicElement) +    (Transition) + +    //bibliographic elements +    (Author,       TextOrInlineElement) +    (Authors,      AuthorInfo) +    (Organization, TextOrInlineElement) +    (Address,      TextOrInlineElement; +) +    (Contact,      TextOrInlineElement) +    (Version,      TextOrInlineElement) +    (Revision,     TextOrInlineElement) +    (Status,       TextOrInlineElement) +    (Date,         TextOrInlineElement) +    (Copyright,    TextOrInlineElement) +    (Field,        SubField) + +    //decoration elements +    (Header, BodyElement) +    (Footer, BodyElement) + +    //simple body elements +    (Paragraph,              TextOrInlineElement) +    (LiteralBlock,           TextOrInlineElement; +) +    (DoctestBlock,           TextOrInlineElement; +) +    (MathBlock,              String) +    (Rubric,                 TextOrInlineElement) +    (SubstitutionDefinition, TextOrInlineElement; +) +    (Comment,                TextOrInlineElement; +) +    (Pending) +    (Target; +) +    (Raw, String; +) +    (Image; *) + +    //compound body elements +    (Compound,  BodyElement) +    (Container, BodyElement) + +    (BulletList,     ListItem; +) +    (EnumeratedList, ListItem; +) +    (DefinitionList, DefinitionListItem) +    (FieldList,      Field) +    (OptionList,     OptionListItem) + +    (LineBlock,     SubLineBlock) +    (BlockQuote,    SubBlockQuote) +    (Admonition,    SubTopic) +    (Attention,     BodyElement) +    (Hint,          BodyElement) +    (Note,          BodyElement) +    (Caution,       BodyElement) +    (Danger,        BodyElement) +    (Error,         BodyElement) +    (Important,     BodyElement) +    (Tip,           BodyElement) +    (Warning,       BodyElement) +    (Footnote,      SubFootnote; +) +    (Citation,      SubFootnote; +) +    (SystemMessage, BodyElement; +) +    (Figure,        SubFigure;   +) +    (Table,         SubTable;    +) + +    //table elements +    (TableGroup, SubTableGroup; +) +    (TableHead,  TableRow;      +) +    (TableBody,  TableRow;      +) +    (TableRow,   TableEntry;    +) +    (TableEntry, BodyElement;   +) +    (TableColspec; +) + +    //body sub elements +    (ListItem, BodyElement) + +    (DefinitionListItem, SubDLItem) +    (Term,               TextOrInlineElement) +    (Classifier,         TextOrInlineElement) +    (Definition,         BodyElement) + +    (FieldName, TextOrInlineElement) +    (FieldBody, BodyElement) + +    (OptionListItem, SubOptionListItem) +    (OptionGroup,    Option_) +    (Description,    BodyElement) +    (Option_,        SubOption) +    (OptionString,   String) +    (OptionArgument, String; +) + +    (Line,        TextOrInlineElement) +    (Attribution, TextOrInlineElement) +    (Label,       TextOrInlineElement) + +    (Caption, TextOrInlineElement) +    (Legend,  BodyElement) + +    //inline elements +    (Emphasis,              TextOrInlineElement) +    (Literal,               String) +    (Reference,             TextOrInlineElement; +) +    (Strong,                TextOrInlineElement) +    (FootnoteReference,     TextOrInlineElement; +) +    (CitationReference,     TextOrInlineElement; +) +    (SubstitutionReference, TextOrInlineElement; +) +    (TitleReference,        TextOrInlineElement) +    (Abbreviation,          TextOrInlineElement) +    (Acronym,               TextOrInlineElement) +    (Superscript,           TextOrInlineElement) +    (Subscript,             TextOrInlineElement) +    (Inline,                TextOrInlineElement) +    (Problematic,           TextOrInlineElement; +) +    (Generated,             TextOrInlineElement) +    (Math,                  String) + +    //also have non-inline versions. Inline image is no figure child, inline target has content +    (TargetInline, String; +) +    (RawInline,    String; +) +    (ImageInline; *) + +    //text element = String  );  impl<'a> From<&'a str> for TextOrInlineElement { -	fn from(s: &'a str) -> Self { -		s.to_owned().into() -	} +    fn from(s: &'a str) -> Self { +        s.to_owned().into() +    }  } diff --git a/document_tree/src/extra_attributes.rs b/document_tree/src/extra_attributes.rs index 45fcf32..9dcabd7 100644 --- a/document_tree/src/extra_attributes.rs +++ b/document_tree/src/extra_attributes.rs @@ -1,62 +1,60 @@  use serde_derive::Serialize; -use crate::url::Url;  use crate::attribute_types::{ -	CanBeEmpty, -	FixedSpace, -	ID,NameToken, -	AlignHV,AlignH,AlignV, -	TableAlignH,TableBorder,TableGroupCols, -	Measure, -	EnumeratedListType, +    AlignH, AlignHV, AlignV, CanBeEmpty, EnumeratedListType, FixedSpace, Measure, NameToken, +    TableAlignH, TableBorder, TableGroupCols, ID,  }; +use crate::url::Url;  pub trait ExtraAttributes<A> { -	fn with_extra(extra: A) -> Self; -	fn extra    (&    self) -> &    A; -	fn extra_mut(&mut self) -> &mut A; +    fn with_extra(extra: A) -> Self; +    fn extra(&self) -> &A; +    fn extra_mut(&mut self) -> &mut A;  }  macro_rules! impl_extra { -	( $name:ident { $( $(#[$pattr:meta])* $param:ident : $type:ty ),* $(,)* } ) => ( -		impl_extra!( -			#[derive(Default,Debug,PartialEq,Serialize,Clone)] -			$name { $( $(#[$pattr])* $param : $type, )* } -		); -	); -	( $(#[$attr:meta])+ $name:ident { $( $(#[$pattr:meta])* $param:ident : $type:ty ),* $(,)* } ) => ( -		$(#[$attr])+ -		pub struct $name { $( -			$(#[$pattr])* -			#[serde(skip_serializing_if = "CanBeEmpty::is_empty")] -			pub $param : $type, -		)* } -	); +    ( $name:ident { $( $(#[$pattr:meta])* $param:ident : $type:ty ),* $(,)* } ) => ( +        impl_extra!( +            #[derive(Default,Debug,PartialEq,Serialize,Clone)] +            $name { $( $(#[$pattr])* $param : $type, )* } +        ); +    ); +    ( $(#[$attr:meta])+ $name:ident { $( $(#[$pattr:meta])* $param:ident : $type:ty ),* $(,)* } ) => ( +        $(#[$attr])+ +        pub struct $name { $( +            $(#[$pattr])* +            #[serde(skip_serializing_if = "CanBeEmpty::is_empty")] +            pub $param : $type, +        )* } +    );  }  impl_extra!(Address { space: FixedSpace });  impl_extra!(LiteralBlock { space: FixedSpace });  impl_extra!(DoctestBlock { space: FixedSpace }); -impl_extra!(SubstitutionDefinition { ltrim: bool, rtrim: bool }); +impl_extra!(SubstitutionDefinition { +    ltrim: bool, +    rtrim: bool +});  impl_extra!(Comment { space: FixedSpace });  impl_extra!(Target { -	/// External reference to a URI/URL -	refuri: Option<Url>, -	/// References to ids attributes in other elements -	refid: Option<ID>, -	/// Internal reference to the names attribute of another element. May resolve to either an internal or external reference. -	refname: Vec<NameToken>, -	anonymous: bool, +    /// External reference to a URI/URL +    refuri: Option<Url>, +    /// References to ids attributes in other elements +    refid: Option<ID>, +    /// Internal reference to the names attribute of another element. May resolve to either an internal or external reference. +    refname: Vec<NameToken>, +    anonymous: bool,  });  impl_extra!(Raw { space: FixedSpace, format: Vec<NameToken> });  impl_extra!(#[derive(Debug,PartialEq,Serialize,Clone)] Image { -	uri: Url, -	align: Option<AlignHV>, -	alt: Option<String>, -	height: Option<Measure>, -	width: Option<Measure>, -	scale: Option<u8>, -	target: Option<Url>,  // Not part of the DTD but a valid argument +    uri: Url, +    align: Option<AlignHV>, +    alt: Option<String>, +    height: Option<Measure>, +    width: Option<Measure>, +    scale: Option<u8>, +    target: Option<Url>,  // Not part of the DTD but a valid argument  });  //bools usually are XML yesorno. “auto” however either exists and is set to something random like “1” or doesn’t exist @@ -81,13 +79,13 @@ impl_extra!(TableColspec { colnum: Option<usize>, colname: Option<NameToken>, co  impl_extra!(OptionArgument { delimiter: Option<String> });  impl_extra!(Reference { -	name: Option<NameToken>,  //TODO: is CDATA in the DTD, so maybe no nametoken? -	/// External reference to a URI/URL -	refuri: Option<Url>, -	/// References to ids attributes in other elements -	refid: Option<ID>, -	/// Internal reference to the names attribute of another element -	refname: Vec<NameToken>, +    name: Option<NameToken>,  //TODO: is CDATA in the DTD, so maybe no nametoken? +    /// External reference to a URI/URL +    refuri: Option<Url>, +    /// References to ids attributes in other elements +    refid: Option<ID>, +    /// Internal reference to the names attribute of another element +    refname: Vec<NameToken>,  });  impl_extra!(FootnoteReference { refid: Option<ID>, refname: Vec<NameToken>, auto: bool });  impl_extra!(CitationReference { refid: Option<ID>, refname: Vec<NameToken> }); @@ -96,25 +94,27 @@ impl_extra!(Problematic { refid: Option<ID> });  //also have non-inline versions. Inline image is no figure child, inline target has content  impl_extra!(TargetInline { -	/// External reference to a URI/URL -	refuri: Option<Url>, -	/// References to ids attributes in other elements -	refid: Option<ID>, -	/// Internal reference to the names attribute of another element. May resolve to either an internal or external reference. -	refname: Vec<NameToken>, -	anonymous: bool, +    /// External reference to a URI/URL +    refuri: Option<Url>, +    /// References to ids attributes in other elements +    refid: Option<ID>, +    /// Internal reference to the names attribute of another element. May resolve to either an internal or external reference. +    refname: Vec<NameToken>, +    anonymous: bool,  });  impl_extra!(RawInline { space: FixedSpace, format: Vec<NameToken> });  pub type ImageInline = Image;  impl Image { -	pub fn new(uri: Url) -> Image { Image { -		uri, -		align: None, -		alt: None, -		height: None, -		width: None, -		scale: None, -		target: None, -	} } +    pub fn new(uri: Url) -> Image { +        Image { +            uri, +            align: None, +            alt: None, +            height: None, +            width: None, +            scale: None, +            target: None, +        } +    }  } diff --git a/document_tree/src/lib.rs b/document_tree/src/lib.rs index 9154725..4b34ea9 100644 --- a/document_tree/src/lib.rs +++ b/document_tree/src/lib.rs @@ -1,50 +1,52 @@ -#![recursion_limit="256"] +#![recursion_limit = "256"] -///http://docutils.sourceforge.net/docs/ref/doctree.html -///serves as AST +/// See [doctree][] reference. +/// Serves as AST. +/// +/// [doctree]: http://docutils.sourceforge.net/docs/ref/doctree.html  #[macro_use]  mod macro_util; -pub mod url; -pub mod elements; +pub mod attribute_types;  pub mod element_categories; +pub mod elements;  pub mod extra_attributes; -pub mod attribute_types; +pub mod url; +pub use self::element_categories::HasChildren;  pub use self::elements::*; //Element,CommonAttributes,HasExtraAndChildren  pub use self::extra_attributes::ExtraAttributes; -pub use self::element_categories::HasChildren;  #[cfg(test)]  mod tests { -	use super::*; -	use std::default::Default; - -	#[test] -	fn imperative() { -		let mut doc = Document::default(); -		let mut title = Title::default(); -		let url = "https://example.com/image.jpg".parse().unwrap(); -		let image = ImageInline::with_extra(extra_attributes::ImageInline::new(url)); -		title.append_child("Hi"); -		title.append_child(image); -		doc.append_child(title); - -		println!("{:?}", doc); -	} - -	#[test] -	fn descriptive() { -		let doc = Document::with_children(vec![ -			Title::with_children(vec![ -				"Hi".into(), -				ImageInline::with_extra(extra_attributes::ImageInline::new( -					"https://example.com/image.jpg".parse().unwrap() -				)).into(), -			]).into() -		]); - -		println!("{:?}", doc); -	} +    use super::*; +    use std::default::Default; + +    #[test] +    fn imperative() { +        let mut doc = Document::default(); +        let mut title = Title::default(); +        let url = "https://example.com/image.jpg".parse().unwrap(); +        let image = ImageInline::with_extra(extra_attributes::ImageInline::new(url)); +        title.append_child("Hi"); +        title.append_child(image); +        doc.append_child(title); + +        println!("{:?}", doc); +    } + +    #[test] +    fn descriptive() { +        let doc = Document::with_children(vec![Title::with_children(vec![ +            "Hi".into(), +            ImageInline::with_extra(extra_attributes::ImageInline::new( +                "https://example.com/image.jpg".parse().unwrap(), +            )) +            .into(), +        ]) +        .into()]); + +        println!("{:?}", doc); +    }  } diff --git a/document_tree/src/macro_util.rs b/document_tree/src/macro_util.rs index dcf3725..e370011 100644 --- a/document_tree/src/macro_util.rs +++ b/document_tree/src/macro_util.rs @@ -1,42 +1,41 @@  macro_rules! cartesian_impl { -	($out:tt [] $b:tt $init_b:tt $submacro:tt) => { -		$submacro!{$out} -	}; -	($out:tt [$a:tt, $($at:tt)*] [] $init_b:tt $submacro:tt) => { -		cartesian_impl!{$out [$($at)*] $init_b $init_b $submacro} -	}; -	([$($out:tt)*] [$a:tt, $($at:tt)*] [$b:tt, $($bt:tt)*] $init_b:tt $submacro:tt) => { -		cartesian_impl!{[$($out)* ($a, $b),] [$a, $($at)*] [$($bt)*] $init_b $submacro} -	}; +    ($out:tt [] $b:tt $init_b:tt $submacro:tt) => { +        $submacro!{$out} +    }; +    ($out:tt [$a:tt, $($at:tt)*] [] $init_b:tt $submacro:tt) => { +        cartesian_impl!{$out [$($at)*] $init_b $init_b $submacro} +    }; +    ([$($out:tt)*] [$a:tt, $($at:tt)*] [$b:tt, $($bt:tt)*] $init_b:tt $submacro:tt) => { +        cartesian_impl!{[$($out)* ($a, $b),] [$a, $($at)*] [$($bt)*] $init_b $submacro} +    };  }  macro_rules! cartesian { -	( $submacro:tt, [$($a:tt)*], [$($b:tt)*]) => { -		cartesian_impl!{[] [$($a)*,] [$($b)*,] [$($b)*,] $submacro} -	}; +    ( $submacro:tt, [$($a:tt)*], [$($b:tt)*]) => { +        cartesian_impl!{[] [$($a)*,] [$($b)*,] [$($b)*,] $submacro} +    };  } -  #[cfg(test)]  mod tests { -	macro_rules! print_cartesian { -		( [ $(($a1:tt, $a2:tt)),* , ] ) => { -			fn test_f(x:i64, y:i64) -> Result<(i64, i64), ()> { -				match (x, y) { -				$( -					($a1, $a2) => { Ok(($a1, $a2)) } -				)* -				_ => { Err(()) } -				} -			} -		}; -	} +    macro_rules! print_cartesian { +        ( [ $(($a1:tt, $a2:tt)),* , ] ) => { +            fn test_f(x:i64, y:i64) -> Result<(i64, i64), ()> { +                match (x, y) { +                $( +                    ($a1, $a2) => { Ok(($a1, $a2)) } +                )* +                _ => { Err(()) } +                } +            } +        }; +    } -	#[test] -	fn print_cartesian() { -		cartesian!(print_cartesian, [1, 2, 3], [4, 5, 6]); -		assert_eq!(test_f(1, 4), Ok((1, 4))); -		assert_eq!(test_f(1, 3), Err(())); -		assert_eq!(test_f(3, 5), Ok((3, 5))); -	} +    #[test] +    fn print_cartesian() { +        cartesian!(print_cartesian, [1, 2, 3], [4, 5, 6]); +        assert_eq!(test_f(1, 4), Ok((1, 4))); +        assert_eq!(test_f(1, 3), Err(())); +        assert_eq!(test_f(3, 5), Ok((3, 5))); +    }  } diff --git a/document_tree/src/url.rs b/document_tree/src/url.rs index 31a0536..be320e9 100644 --- a/document_tree/src/url.rs +++ b/document_tree/src/url.rs @@ -1,78 +1,74 @@  use std::fmt;  use std::str::FromStr; -use url::{self,ParseError};  use serde_derive::Serialize; - +use url::{self, ParseError};  fn starts_with_scheme(input: &str) -> bool { -	let scheme = input.split(':').next().unwrap(); -	if scheme == input || scheme.is_empty() { -		return false; -	} -	let mut chars = input.chars(); -	// First character. -	if !chars.next().unwrap().is_ascii_alphabetic() { -		return false; -	} -	for ch in chars { -		if !ch.is_ascii_alphanumeric() && ch != '+' && ch != '-' && ch != '.' { -			return false; -		} -	} -	true +    let scheme = input.split(':').next().unwrap(); +    if scheme == input || scheme.is_empty() { +        return false; +    } +    let mut chars = input.chars(); +    // First character. +    if !chars.next().unwrap().is_ascii_alphabetic() { +        return false; +    } +    for ch in chars { +        if !ch.is_ascii_alphanumeric() && ch != '+' && ch != '-' && ch != '.' { +            return false; +        } +    } +    true  }  /// The string representation of a URL, either absolute or relative, that has  /// been verified as a valid URL on construction. -#[derive(Debug,PartialEq,Serialize,Clone)] +#[derive(Debug, PartialEq, Serialize, Clone)]  #[serde(transparent)]  pub struct Url(String);  impl Url { -	pub fn parse_absolute(input: &str) -> Result<Self, ParseError> { -		Ok(url::Url::parse(input)?.into()) -	} -	pub fn parse_relative(input: &str) -> Result<Self, ParseError> { -		// We're assuming that any scheme through which RsT documents are being -		// accessed is a hierarchical scheme, and so we can parse relative to a -		// random hierarchical URL. -		if input.starts_with('/') || !starts_with_scheme(input) { -			// Continue only if the parse succeeded, disregarding its result. -			let random_base_url = url::Url::parse("https://a/b").unwrap(); -			url::Url::options() -				.base_url(Some(&random_base_url)) -				.parse(input)?; -			Ok(Url(input.into())) -		} else { -			// If this is a URL at all, it's an absolute one. -			// There's no appropriate variant of url::ParseError really. -			Err(ParseError::SetHostOnCannotBeABaseUrl) -		} -	} -	pub fn as_str(&self) -> &str { -		self.0.as_str() -	} +    pub fn parse_absolute(input: &str) -> Result<Self, ParseError> { +        Ok(url::Url::parse(input)?.into()) +    } +    pub fn parse_relative(input: &str) -> Result<Self, ParseError> { +        // We're assuming that any scheme through which RsT documents are being +        // accessed is a hierarchical scheme, and so we can parse relative to a +        // random hierarchical URL. +        if input.starts_with('/') || !starts_with_scheme(input) { +            // Continue only if the parse succeeded, disregarding its result. +            let random_base_url = url::Url::parse("https://a/b").unwrap(); +            url::Url::options() +                .base_url(Some(&random_base_url)) +                .parse(input)?; +            Ok(Url(input.into())) +        } else { +            // If this is a URL at all, it's an absolute one. +            // There's no appropriate variant of url::ParseError really. +            Err(ParseError::SetHostOnCannotBeABaseUrl) +        } +    } +    pub fn as_str(&self) -> &str { +        self.0.as_str() +    }  }  impl From<url::Url> for Url { -	fn from(url: url::Url) -> Self { -		Url(url.into_string()) -	} +    fn from(url: url::Url) -> Self { +        Url(url.into()) +    }  } -  impl fmt::Display for Url { -	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -		write!(f, "{}", self.as_str()) -	} +    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +        write!(f, "{}", self.as_str()) +    }  } -  impl FromStr for Url { -	type Err = ParseError; -	fn from_str(input: &str) -> Result<Self, Self::Err> { -		Url::parse_absolute(input) -			.or_else(|_| Url::parse_relative(input)) -	} +    type Err = ParseError; +    fn from_str(input: &str) -> Result<Self, Self::Err> { +        Url::parse_absolute(input).or_else(|_| Url::parse_relative(input)) +    }  } | 
