diff options
| author | Philipp A | 2023-12-28 15:43:24 +0100 |
|---|---|---|
| committer | GitHub | 2023-12-28 15:43:24 +0100 |
| commit | 0f4f1a420cbcf263a9118ec9b288c95f1b59ade8 (patch) | |
| tree | 030abd05e8894e4e9c6775794f890180cf6c5e91 /document_tree/src | |
| parent | 38b1c488601cfc2479f02df555b135ef01aa5618 (diff) | |
| parent | 774dd4798aedc40b38c6480e9c47f34c482f12d0 (diff) | |
| download | rust-rst-0f4f1a420cbcf263a9118ec9b288c95f1b59ade8.tar.bz2 | |
Merge branch 'main' into allow-rst-to-read-from-stdin
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)) + } } |
