#![warn(missing_docs)]
#![allow(rustdoc::private_intra_doc_links)]
mod common;
mod compound;
mod enums;
mod error_message;
mod field;
mod meta;
mod structs;
mod types;
mod wrapped;
use proc_macro::TokenStream as RawTokenStream;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::*;
use self::common::{FromEventsParts, IntoEventIterParts, ItemDef};
fn fail_generics(generics: &Generics) -> Result<()> {
if generics.params.len() > 0 {
return Err(Error::new_spanned(
&generics.params,
"generic parameters are not supported in FromXml/IntoXml/DynNamespace derivations",
));
}
if let Some(where_clause) = generics.where_clause.as_ref() {
return Err(Error::new_spanned(
where_clause,
"where clauses are not supported in FromXml/IntoXml/DynNamespace derivations",
));
}
Ok(())
}
fn parse(item: Item) -> Result<(Visibility, Box<dyn ItemDef>, Ident)> {
match item {
Item::Struct(item) => {
let def = self::structs::parse_struct(&item)?;
let ident = item.ident;
fail_generics(&item.generics)?;
Ok((item.vis, def, ident))
}
Item::Enum(item) => {
let def = self::enums::parse_enum(&item)?;
let ident = item.ident;
fail_generics(&item.generics)?;
Ok((item.vis, def, ident))
}
other => Err(Error::new_spanned(
other,
"can only be applied to enum and struct definitions",
)),
}
}
fn try_from_element_impl(item: Item) -> Result<TokenStream> {
let (vis, def, ident) = parse(item)?;
let ty = Type::Path(TypePath {
qself: None,
path: Path {
leading_colon: None,
segments: [PathSegment {
ident: ident.clone(),
arguments: PathArguments::None,
}]
.into_iter()
.collect(),
},
});
let FromEventsParts {
struct_def,
from_events_body,
builder_ty_ident,
} = def.build_from_events_builder(
&vis,
&ty,
&(Path::from(ident.clone()).into()),
&Ident::new("name", Span::call_site()),
&Ident::new("attrs", Span::call_site()),
)?;
let result = quote! {
#struct_def
impl ::xso::FromXml for #ty {
type Builder = #builder_ty_ident;
fn from_events(
name: ::xso::exports::rxml::QName,
attrs: ::xso::exports::rxml::AttrMap,
) -> ::std::result::Result<Self::Builder, ::xso::FromEventsError> {
#from_events_body
}
}
impl ::std::convert::TryFrom<::xso::exports::minidom::Element> for #ty {
type Error = ::xso::error::Error;
fn try_from(other: ::xso::exports::minidom::Element) -> ::std::result::Result<Self, Self::Error> {
::xso::try_from_element(other)
}
}
};
if def.debug_mode() {
println!("{}", result);
}
Ok(result)
}
#[proc_macro_derive(FromXml, attributes(xml))]
pub fn try_from_element(input: RawTokenStream) -> RawTokenStream {
let item = syn::parse_macro_input!(input as Item);
let result = try_from_element_impl(item);
match result {
Ok(v) => v.into(),
Err(e) => e.into_compile_error().into(),
}
}
fn dyn_namespace_impl(item: Item) -> Result<TokenStream> {
let (_, def, ident) = parse(item)?;
let dyn_namespace_impl = def.build_dyn_namespace()?;
let result = quote! {
impl ::xso::DynNamespace for #ident {
#dyn_namespace_impl
}
};
if def.debug_mode() {
println!("{}", result);
}
Ok(result)
}
#[proc_macro_derive(DynNamespace, attributes(xml))]
pub fn dyn_namespace(input: RawTokenStream) -> RawTokenStream {
let item = syn::parse_macro_input!(input as Item);
let result = dyn_namespace_impl(item);
match result {
Ok(v) => v.into(),
Err(e) => e.into_compile_error().into(),
}
}
fn into_element_impl(item: Item) -> Result<TokenStream> {
let (vis, def, ident) = parse(item)?;
let ty = Type::Path(TypePath {
qself: None,
path: Path {
leading_colon: None,
segments: [PathSegment {
ident: ident.clone(),
arguments: PathArguments::None,
}]
.into_iter()
.collect(),
},
});
let IntoEventIterParts {
struct_def,
into_event_iter_body,
event_iter_ty_ident,
} = def.build_into_events_iterator(
&vis,
&ty,
&(Path::from(ident.clone()).into()),
&(Ident::new("self", Span::call_site())),
)?;
let result = quote! {
#struct_def
impl ::xso::IntoXml for #ty {
type EventIter = #event_iter_ty_ident;
fn into_event_iter(mut self) -> Result<Self::EventIter, ::xso::error::Error> {
#into_event_iter_body
}
}
};
#[cfg(feature = "panicking-into-impl")]
let result = quote! {
#result
impl ::std::convert::From<#ty> for ::xso::exports::minidom::Element {
fn from(other: #ty) -> Self {
::xso::transform(other).expect("conversion to minidom::Element failed")
}
}
};
#[cfg(not(feature = "panicking-into-impl"))]
let result = quote! {
#result
impl ::std::convert::TryFrom<#ty> for ::xso::exports::minidom::Element {
type Error = ::xso::error::Error;
fn try_from(other: #ty) -> ::std::result::Result<Self, Self::Error> {
::xso::transform(other)
}
}
};
if def.debug_mode() {
println!("{}", result);
}
Ok(result)
}
#[proc_macro_derive(IntoXml, attributes(xml))]
pub fn into_element(input: RawTokenStream) -> RawTokenStream {
let item = syn::parse_macro_input!(input as Item);
let result = into_element_impl(item);
match result {
Ok(v) => v.into(),
Err(e) => e.into_compile_error().into(),
}
}