use std::fmt::Write;
use proc_macro2::TokenStream;
use quote::{quote, ToTokens};
use super::*;
fn escape(s: &str) -> String {
s.chars().fold(String::new(), |mut s, ch| match ch {
'<' => s + "<",
'>' => s + ">",
'&' => s + "&",
'\'' => s + "'",
'"' => s + """,
_ => { write!(&mut s, "{ch}").unwrap(); s },
})
}
impl ToTokens for Xml {
fn to_tokens(&self, tokens: &mut TokenStream) {
let inner = &self.0;
let s = quote! {
inline_xml::Xml(vec![#(#inner),*]).flattened()
};
tokens.extend(s)
}
}
impl ToTokens for Name {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.to_string().to_tokens(tokens)
}
}
impl ToTokens for Tag {
fn to_tokens(&self, tokens: &mut TokenStream) {
let name = &self.name;
let attrs = &self.attrs;
let inner = match &self.tail {
TagTail::Simple { .. } => quote! { None },
TagTail::Complex { inner, .. } => {
quote! {
Some(#inner)
}
}
};
let s = quote! {
inline_xml::Tag {
name: #name.into(),
attrs: vec![#(#attrs),*],
inner: #inner,
}
};
tokens.extend(s);
}
}
impl ToTokens for Attr {
fn to_tokens(&self, tokens: &mut TokenStream) {
let name = &self.name;
let value = &self.value;
let s = quote! {
inline_xml::Attr {
name: #name.into(),
value: #value,
}
};
tokens.extend(s)
}
}
impl ToTokens for Content {
fn to_tokens(&self, tokens: &mut TokenStream) {
let s = match self {
Self::Tag(t) => quote! { inline_xml::Content::Tag(#t) },
Self::Ident(i) => quote! { inline_xml::Content::Word(stringify!(#i).into()) },
Self::Int(i) => quote! { inline_xml::Content::Word(stringify!(#i).into()) },
Self::Float(f) => quote! { inline_xml::Content::Word(stringify!(#f).into()) },
Self::Punct(p) => quote! { inline_xml::Content::Word(stringify!(#p).into()) },
Self::Str(s) => {
let s = escape(&s.value());
quote! {
inline_xml::Content::Word(#s.into())
}
},
Self::Block(b) => quote! {
inline_xml::Content::Nested({ use inline_xml::ToXml; #b.to_xml() })
},
Self::Escape { escape, .. } => {
let s = match escape {
Escape::Lt(_) => "lt".to_owned(),
Escape::Gt(_) => "gt".to_owned(),
Escape::Amp(_) => "amp".to_owned(),
Escape::Apos(_) => "apos".to_owned(),
Escape::Quot(_) => "quot".to_owned(),
Escape::Int { lit, .. } => format!("#{}", lit),
Escape::X { value, .. } => format!("#x{:x}", value),
};
let s = format!("&{s};");
quote! {
inline_xml::Content::Word(#s.into())
}
},
};
tokens.extend(s)
}
}
impl ToTokens for Value {
fn to_tokens(&self, tokens: &mut TokenStream) {
let s = match self {
Self::Str(s) => quote! { #s.into() },
Self::Block(b) => quote! { #b.to_string() }
};
tokens.extend(s)
}
}