#![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 wrapped;
use proc_macro::TokenStream as RawTokenStream;
use proc_macro2::{Span, TokenStream};
use quote::quote;
use syn::*;
use self::common::bake_generics;
use self::common::ItemDef;
fn parse(
item: Item,
) -> Result<(
Box<dyn ItemDef>,
Ident,
TokenStream,
TokenStream,
Option<WhereClause>,
)> {
match item {
Item::Struct(item) => {
let def = self::structs::parse_struct(&item)?;
let ident = item.ident;
let (generics_decl, generics_ref, where_clause) = bake_generics(item.generics);
Ok((def, ident, generics_decl, generics_ref, where_clause))
}
Item::Enum(item) => {
let def = self::enums::parse_enum(&item)?;
let ident = item.ident;
let (generics_decl, generics_ref, where_clause) = bake_generics(item.generics);
Ok((def, ident, generics_decl, generics_ref, where_clause))
}
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 (def, ident, generics_decl, generics_ref, where_clause) = parse(item)?;
let try_from_impl = def.build_try_from_element(
&(Path::from(ident.clone()).into()),
&Ident::new("residual", Span::call_site()),
)?;
Ok(quote! {
#[allow(non_snake_case)]
impl #generics_decl ::std::convert::TryFrom<::xso::exports::minidom::Element> for #ident #generics_ref #where_clause {
type Error = ::xso::error::Error;
fn try_from(mut residual: ::xso::exports::minidom::Element) -> Result<Self, Self::Error> {
#try_from_impl
}
}
impl #generics_decl ::xso::FromXml for #ident #generics_ref #where_clause {
fn from_tree(elem: ::xso::exports::minidom::Element) -> Result<Self, ::xso::error::Error> {
Self::try_from(elem)
}
fn absent() -> Option<Self> {
None
}
}
})
}
#[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, generics_decl, generics_ref, where_clause) = parse(item)?;
let dyn_namespace_impl = def.build_dyn_namespace()?;
Ok(quote! {
#[allow(non_snake_case)]
impl #generics_decl ::xso::DynNamespace for #ident #generics_ref #where_clause {
#dyn_namespace_impl
}
})
}
#[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 (def, ident, generics_decl, generics_ref, where_clause) = parse(item)?;
let into_element_impl = def.build_into_element(
&(Path::from(ident.clone()).into()),
&Ident::new("other", Span::call_site()),
)?;
Ok(quote! {
#[allow(non_snake_case)]
impl #generics_decl ::std::convert::From<#ident #generics_ref> for ::xso::exports::minidom::Element #where_clause {
fn from(mut other: #ident #generics_ref) -> Self {
#into_element_impl
}
}
impl #generics_decl ::xso::IntoXml for #ident #generics_ref {
fn into_tree(self) -> Option<::xso::exports::minidom::Element> {
Some(::xso::exports::minidom::Element::from(self))
}
}
})
}
#[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(),
}
}