use std::io; use tokio::io::{AsyncWrite, AsyncWriteExt}; use super::{ AttValue, AttValueData, CDEnd, CDSect, CDStart, CData, Char, CharData, Comment, DeclSep, DefaultAttName, DoctypeDecl, Document, Element, EntityValue, EntityValueData, Eq, ExtSubset, ExtSubsetDecl, IntSubset, LocalPart, MarkupDecl, Misc, NCName, NSAttName, Name, NameChar, NameStartChar, Names, Nmtoken, Nmtokens, PITarget, Prefix, PrefixedAttName, PrefixedName, Prolog, PubidChar, PubidLiteral, QName, SDDecl, SystemLiteral, UnprefixedName, VersionInfo, VersionNum, XMLDecl, PI, S, }; /// Compact Composer trait, can create different trait later for pretty composition pub trait Composer<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite; } // namespaces in xml /// [1] NSAttName ::= PrefixedAttName | DefaultAttName impl<'s> Composer<'s> for NSAttName<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: AsyncWrite + Unpin, { match self { NSAttName::PrefixedAttName(prefixed_att_name) => { prefixed_att_name.write(writer).await? } NSAttName::DefaultAttName => DefaultAttName.write(writer).await?, } Ok(()) } } /// [2] PrefixedAttName ::= 'xmlns:' NCName impl<'s> Composer<'s> for PrefixedAttName<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: AsyncWrite + Unpin, { writer.write_all("xmlns:".as_bytes()).await?; self.0.write(writer).await?; Ok(()) } } /// [3] DefaultAttName ::= 'xmlns'; impl Composer<'_> for DefaultAttName { async fn write(&self, writer: &mut W) -> io::Result<()> where W: AsyncWrite + Unpin, { writer.write_all("xmlns".as_bytes()).await?; Ok(()) } } /// [4] NCName ::= Name - (Char* ':' Char*) impl<'s> Composer<'s> for NCName<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: AsyncWrite + Unpin, { writer.write_all(self.0.as_bytes()).await?; Ok(()) } } /// [7] QName ::= PrefixedName | UnprefixedName impl<'s> Composer<'s> for QName<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: AsyncWrite + Unpin, { match self { QName::PrefixedName(prefixed_name) => prefixed_name.write(writer).await?, QName::UnprefixedName(unprefixed_name) => unprefixed_name.write(writer).await?, } Ok(()) } } /// [8] PrefixedName ::= Prefix ':' LocalPart impl<'s> Composer<'s> for PrefixedName<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: AsyncWrite + Unpin, { self.prefix.write(writer).await?; writer.write_all(":".as_bytes()).await?; self.local_part.write(writer).await?; Ok(()) } } /// [9] UnprefixedName ::= LocalPart impl<'s> Composer<'s> for UnprefixedName<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { self.0.write(writer).await?; Ok(()) } } /// [10] Prefix ::= NCName impl<'s> Composer<'s> for Prefix<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { self.0.write(writer).await?; Ok(()) } } /// [11] LocalPart ::= NCName impl<'s> Composer<'s> for LocalPart<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { self.0.write(writer).await?; Ok(()) } } // xml spec /// [1] document ::= prolog element Misc* impl<'s> Composer<'s> for Document<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { self.0.write(writer).await?; self.1.write(writer).await?; for misc in &self.2 { misc.write(writer).await? } Ok(()) } } /// [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */ impl Composer<'_> for Char { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all(self.0.to_string().as_bytes()).await?; Ok(()) } } /// [3] S ::= (#x20 | #x9 | #xD | #xA)+ impl<'s> Composer<'s> for S { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all("\u{20}".as_bytes()).await?; Ok(()) } } /// [4] NameStartChar ::= ":" | [A-Z] | "_" | [a-z] | [#xC0-#xD6] | [#xD8-#xF6] | [#xF8-#x2FF] | [#x370-#x37D] | [#x37F-#x1FFF] | [#x200C-#x200D] | [#x2070-#x218F] | [#x2C00-#x2FEF] | [#x3001-#xD7FF] | [#xF900-#xFDCF] | [#xFDF0-#xFFFD] | [#x10000-#xEFFFF] impl Composer<'_> for NameStartChar { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all(self.0.to_string().as_bytes()).await?; Ok(()) } } /// [4a] NameChar ::= NameStartChar | "-" | "." | [0-9] | #xB7 | [#x0300-#x036F] | [#x203F-#x2040] impl Composer<'_> for NameChar { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all(self.0.to_string().as_bytes()).await?; Ok(()) } } /// [5] Name ::= NameStartChar (NameChar)* impl<'s> Composer<'s> for Name<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all(self.0.as_bytes()).await?; Ok(()) } } /// [6] Names ::= Name (#x20 Name)* impl<'s> Composer<'s> for Names<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { let mut first = true; for name in &self.0 { if !first { writer.write_all("\u{20}".as_bytes()).await?; } name.write(writer).await?; if first { first = false } } Ok(()) } } /// [7] Nmtoken ::= (NameChar)+ impl<'s> Composer<'s> for Nmtoken<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all(self.0.as_bytes()).await?; Ok(()) } } /// [8] Nmtokens ::= Nmtoken (#x20 Nmtoken)* impl<'s> Composer<'s> for Nmtokens<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { let mut first = true; for nmtoken in &self.0 { if !first { writer.write_all("\u{20}".as_bytes()).await?; } nmtoken.write(writer).await?; if first { first = false } } Ok(()) } } /// [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' /// | "'" ([^%&'] | PEReference | Reference)* "'" impl<'s> Composer<'s> for EntityValue<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { match self { EntityValue::DoubleQuoted(entity_value_data) => { writer.write_all("\"".as_bytes()).await?; for entity_value_data in entity_value_data { match entity_value_data { EntityValueData::String(s) => writer.write_all(s.as_bytes()).await?, EntityValueData::PEReference(pe_reference) => { pe_reference.write(writer).await? } EntityValueData::Reference(reference) => reference.write(writer).await?, } } writer.write_all("\"".as_bytes()).await?; } EntityValue::SingleQuoted(entity_value_data) => { writer.write_all("'".as_bytes()).await?; for entity_value_data in entity_value_data { match entity_value_data { EntityValueData::String(s) => writer.write_all(s.as_bytes()).await?, EntityValueData::PEReference(pe_reference) => { pe_reference.write(writer).await? } EntityValueData::Reference(reference) => reference.write(writer).await?, } } writer.write_all("'".as_bytes()).await?; } } Ok(()) } } /// [10] AttValue ::= '"' ([^<&"] | Reference)* '"' /// | "'" ([^<&'] | Reference)* "'" impl<'s> Composer<'s> for AttValue<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { match self { AttValue::DoubleQuoted(att_value_data) => { writer.write_all("\"".as_bytes()).await?; for att_value_data in att_value_data { match att_value_data { AttValueData::String(s) => writer.write_all(s.as_bytes()).await?, AttValueData::Reference(reference) => reference.write(writer).await?, } } writer.write_all("\"".as_bytes()).await?; } AttValue::SingleQuoted(att_value_data) => { writer.write_all("'".as_bytes()).await?; for att_value_data in att_value_data { match att_value_data { AttValueData::String(s) => writer.write_all(s.as_bytes()).await?, AttValueData::Reference(reference) => reference.write(writer).await?, } } writer.write_all("'".as_bytes()).await?; } } Ok(()) } } /// [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'") impl<'s> Composer<'s> for SystemLiteral<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { match self { SystemLiteral::DoubleQuoted(s) => { writer.write_all("\"".as_bytes()).await?; writer.write_all(s.as_bytes()).await?; writer.write_all("\"".as_bytes()).await?; } SystemLiteral::SingleQuoted(s) => { writer.write_all("'".as_bytes()).await?; writer.write_all(s.as_bytes()).await?; writer.write_all("'".as_bytes()).await?; } } Ok(()) } } /// [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'" impl<'s> Composer<'s> for PubidLiteral<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { match self { PubidLiteral::DoubleQuoted(s) => { writer.write_all("\"".as_bytes()).await?; writer.write_all(s.as_bytes()).await?; writer.write_all("\"".as_bytes()).await?; } PubidLiteral::SingleQuoted(s) => { writer.write_all("'".as_bytes()).await?; writer.write_all(s.as_bytes()).await?; writer.write_all("'".as_bytes()).await?; } } Ok(()) } } /// [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%] impl Composer<'_> for PubidChar { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all(self.0.to_string().as_bytes()).await?; Ok(()) } } /// [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*) impl<'s> Composer<'s> for CharData<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all(self.0.as_bytes()).await?; Ok(()) } } /// [15] Comment ::= '' impl<'s> Composer<'s> for Comment<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all("".as_bytes()).await?; Ok(()) } } /// [16] PI ::= '' Char*)))? '?>' impl<'s> Composer<'s> for PI<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all("".as_bytes()).await?; Ok(()) } } /// [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l')) impl<'s> Composer<'s> for PITarget<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { self.0.write(writer).await?; Ok(()) } } /// [18] CDSect ::= CDStart CData CDEnd impl<'s> Composer<'s> for CDSect<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { CDStart.write(writer).await?; self.0.write(writer).await?; CDEnd.write(writer).await?; Ok(()) } } /// [19] CDStart ::= ' for CDStart { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all("' Char*)) impl<'s> Composer<'s> for CData<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all(self.0.as_bytes()).await?; Ok(()) } } /// [21] CDEnd ::= ']]>' impl Composer<'_> for CDEnd { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all("]]>".as_bytes()).await?; Ok(()) } } /// [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)? impl<'s> Composer<'s> for Prolog<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { if let Some(xml_decl) = &self.0 { xml_decl.write(writer).await?; } for misc in &self.1 { misc.write(writer).await?; } if let Some((doctype_decl, miscs)) = &self.2 { doctype_decl.write(writer).await?; for misc in miscs { misc.write(writer).await?; } } Ok(()) } } /// [23] XMLDecl ::= '' impl<'s> Composer<'s> for XMLDecl<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all("".as_bytes()).await?; Ok(()) } } /// [24] VersionInfo ::= S 'version' Eq ("'" VersionNum "'" | '"' VersionNum '"') impl Composer<'_> for VersionInfo { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { S.write(writer).await?; writer.write_all("version".as_bytes()).await?; Eq.write(writer).await?; match self { VersionInfo::SingleQuoted(version_num) => { writer.write_all("'".as_bytes()).await?; version_num.write(writer).await?; writer.write_all("'".as_bytes()).await?; } VersionInfo::DoubleQuoted(version_num) => { writer.write_all("\"".as_bytes()).await?; version_num.write(writer).await?; writer.write_all("\"".as_bytes()).await?; } } Ok(()) } } /// [25] Eq ::= S? '=' S? impl Composer<'_> for Eq { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all("=".as_bytes()).await?; Ok(()) } } /// [26] VersionNum ::= '1.' [0-9]+ impl Composer<'_> for VersionNum { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { match self { VersionNum::One => writer.write_all("1.0".as_bytes()).await?, VersionNum::OneDotOne => writer.write_all("1.1".as_bytes()).await?, } Ok(()) } } /// [27] Misc ::= Comment | PI | S impl<'s> Composer<'s> for Misc<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { match self { Misc::Comment(comment) => comment.write(writer).await?, Misc::PI(pi) => pi.write(writer).await?, Misc::S => {} } Ok(()) } } /// [16] doctypedecl ::= '' /// [28] doctypedecl ::= '' impl<'s> Composer<'s> for DoctypeDecl<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { writer.write_all("".as_bytes()).await?; Ok(()) } } /// [28a] DeclSep ::= PEReference | S impl<'s> Composer<'s> for DeclSep<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { match self { DeclSep::PEReference(pe_reference) => pe_reference.write(writer).await?, DeclSep::S => S.write(writer).await?, } Ok(()) } } /// [28b] intSubset ::= (markupdecl | DeclSep)* impl<'s> Composer<'s> for IntSubset<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { for declaration in self { match declaration { super::IntSubsetDeclaration::MarkupDecl(markup_decl) => { markup_decl.write(writer).await? } super::IntSubsetDeclaration::DeclSep(decl_sep) => decl_sep.write(writer).await?, } } Ok(()) } } /// [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl | NotationDecl | PI | Comment impl<'s> Composer<'s> for MarkupDecl<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { match self { MarkupDecl::Elementdecl(elementdecl) => elementdecl.write(writer).await?, MarkupDecl::AttlistDecl(attlist_decl) => attlist_decl.write(writer).await?, MarkupDecl::EntityDecl(entity_decl) => entity_decl.write(writer).await?, MarkupDecl::NotationDecl(notation_decl) => notation_decl.write(writer).await?, MarkupDecl::PI(pi) => pi.write(writer).await?, MarkupDecl::Comment(comment) => comment.write(writer).await?, } Ok(()) } } /// [30] extSubset ::= TextDecl? extSubsetDecl impl<'s> Composer<'s> for ExtSubset<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { if let Some(text_decl) = self.text_decl { text_decl.write(writer).await? } self.ext_subset_decl.write(writer).await?; Ok(()) } } /// [31] extSubsetDecl ::= ( markupdecl | conditionalSect | DeclSep)* impl<'s> Composer<'s> for ExtSubsetDecl<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { for declaration in self { match declaration { super::ExtSubsetDeclaration::MarkupDecl(markup_decl) => { markup_decl.write(writer).await? } super::ExtSubsetDeclaration::ConditionalSect(conditional_sect) => { conditional_sect.write(writer).await? } super::ExtSubsetDeclaration::DeclSep(decl_sep) => decl_sep.write(writer).await?, } } Ok(()) } } /// [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no') '"')) impl Composer<'_> for SDDecl { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { S.write(writer).await?; writer.write_all("standalone".as_bytes()).await?; Eq.write(writer).await?; match self { SDDecl::SingleQuoted(sd_decl) => { writer.write_all("'".as_bytes()).await?; match sd_decl { true => writer.write_all("yes".as_bytes()).await?, false => writer.write_all("no".as_bytes()).await?, } writer.write_all("'".as_bytes()).await?; } SDDecl::DoubleQuoted(sd_decl) => { writer.write_all("\"".as_bytes()).await?; match sd_decl { true => writer.write_all("yes".as_bytes()).await?, false => writer.write_all("no".as_bytes()).await?, } writer.write_all("\"".as_bytes()).await?; } } Ok(()) } } /// [39] element ::= EmptyElemTag | STag content ETag impl<'s> Composer<'s> for Element<'s> { async fn write(&self, writer: &mut W) -> io::Result<()> where W: Unpin + AsyncWrite, { todo!() } }