1#![forbid(unsafe_code)]
8#![warn(missing_docs)]
9#![allow(rustdoc::private_intra_doc_links)]
10#![cfg_attr(docsrs, feature(doc_cfg))]
11#![cfg_attr(docsrs, doc(auto_cfg))]
12use proc_macro::TokenStream as RawTokenStream;
26use proc_macro2::{Span, TokenStream};
27use quote::quote;
28use syn::*;
29
30mod common;
31mod compound;
32mod enums;
33mod error_message;
34mod field;
35mod meta;
36mod scope;
37mod state;
38mod structs;
39mod types;
40
41use common::{AsXmlParts, FromXmlParts, ItemDef};
42
43fn parse_struct(item: Item) -> Result<(Visibility, Ident, Box<dyn ItemDef>)> {
48 match item {
49 Item::Struct(item) => {
50 let meta = meta::XmlCompoundMeta::parse_from_attributes(&item.attrs)?;
51 let def = structs::StructDef::new(&item.ident, meta, &item.fields)?;
52 Ok((item.vis, item.ident, Box::new(def)))
53 }
54 Item::Enum(item) => {
55 let meta = meta::XmlCompoundMeta::parse_from_attributes(&item.attrs)?;
56 let def = enums::EnumDef::new(&item.ident, meta, &item.variants)?;
57 Ok((item.vis, item.ident, Box::new(def)))
58 }
59 other => Err(Error::new_spanned(other, "cannot derive on this item")),
60 }
61}
62
63fn from_xml_impl(input: Item) -> Result<TokenStream> {
66 let (vis, ident, def) = parse_struct(input)?;
67
68 let name_ident = Ident::new("name", Span::call_site());
69 let attrs_ident = Ident::new("attrs", Span::call_site());
70
71 let FromXmlParts {
72 defs,
73 from_events_body,
74 builder_ty_ident,
75 name_matcher,
76 } = def.make_from_events_builder(&vis, &name_ident, &attrs_ident)?;
77
78 #[cfg_attr(not(feature = "minidom"), allow(unused_mut))]
79 let mut result = quote! {
80 #defs
81
82 impl ::xso::FromXml for #ident {
83 type Builder = #builder_ty_ident;
84 const XML_NAME_MATCHER: ::xso::fromxml::XmlNameMatcher<'static> = #name_matcher;
85
86 fn from_events(
87 name: ::xso::exports::rxml::QName,
88 attrs: ::xso::exports::rxml::AttrMap,
89 ctx: &::xso::Context<'_>,
90 ) -> ::core::result::Result<Self::Builder, ::xso::error::FromEventsError> {
91 #from_events_body
92 }
93 }
94 };
95
96 #[cfg(feature = "minidom")]
97 result.extend(quote! {
98 impl ::core::convert::TryFrom<::xso::exports::minidom::Element> for #ident {
99 type Error = ::xso::error::FromElementError;
100
101 fn try_from(other: ::xso::exports::minidom::Element) -> ::core::result::Result<Self, ::xso::error::FromElementError> {
102 ::xso::try_from_element(other)
103 }
104 }
105 });
106
107 if def.debug() {
108 println!("{}", result);
109 }
110
111 Ok(result)
112}
113
114#[proc_macro_derive(FromXml, attributes(xml))]
118pub fn from_xml(input: RawTokenStream) -> RawTokenStream {
119 let item = syn::parse_macro_input!(input as Item);
122 match from_xml_impl(item) {
123 Ok(v) => v.into(),
124 Err(e) => e.into_compile_error().into(),
125 }
126}
127
128fn as_xml_impl(input: Item) -> Result<TokenStream> {
131 let (vis, ident, def) = parse_struct(input)?;
132
133 let AsXmlParts {
134 defs,
135 as_xml_iter_body,
136 item_iter_ty_lifetime,
137 item_iter_ty,
138 } = def.make_as_xml_iter(&vis)?;
139
140 #[cfg_attr(not(feature = "minidom"), allow(unused_mut))]
141 let mut result = quote! {
142 #defs
143
144 impl ::xso::AsXml for #ident {
145 type ItemIter<#item_iter_ty_lifetime> = #item_iter_ty;
146
147 fn as_xml_iter(&self) -> ::core::result::Result<Self::ItemIter<'_>, ::xso::error::Error> {
148 #as_xml_iter_body
149 }
150 }
151 };
152
153 #[cfg(all(feature = "minidom", feature = "panicking-into-impl"))]
154 result.extend(quote! {
155 impl ::core::convert::From<#ident> for ::xso::exports::minidom::Element {
156 fn from(other: #ident) -> Self {
157 ::xso::transform(&other).expect("seamless conversion into minidom::Element")
158 }
159 }
160
161 impl ::core::convert::From<&#ident> for ::xso::exports::minidom::Element {
162 fn from(other: &#ident) -> Self {
163 ::xso::transform(other).expect("seamless conversion into minidom::Element")
164 }
165 }
166 });
167
168 #[cfg(all(feature = "minidom", not(feature = "panicking-into-impl")))]
169 result.extend(quote! {
170 impl ::core::convert::TryFrom<#ident> for ::xso::exports::minidom::Element {
171 type Error = ::xso::error::Error;
172
173 fn try_from(other: #ident) -> ::core::result::Result<Self, Self::Error> {
174 ::xso::transform(&other)
175 }
176 }
177 impl ::core::convert::TryFrom<&#ident> for ::xso::exports::minidom::Element {
178 type Error = ::xso::error::Error;
179
180 fn try_from(other: &#ident) -> ::core::result::Result<Self, Self::Error> {
181 ::xso::transform(other)
182 }
183 }
184 });
185
186 if def.debug() {
187 println!("{}", result);
188 }
189
190 Ok(result)
191}
192
193#[proc_macro_derive(AsXml, attributes(xml))]
197pub fn as_xml(input: RawTokenStream) -> RawTokenStream {
198 let item = syn::parse_macro_input!(input as Item);
201 match as_xml_impl(item) {
202 Ok(v) => v.into(),
203 Err(e) => e.into_compile_error().into(),
204 }
205}