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, GenericsInfo, ItemDef};
42
43fn parse_struct(item: Item) -> Result<(Visibility, Ident, Box<dyn ItemDef>, GenericsInfo)> {
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 let generics = GenericsInfo::bake(item.generics);
53 Ok((item.vis, item.ident, Box::new(def), generics))
54 }
55 Item::Enum(item) => {
56 let meta = meta::XmlCompoundMeta::parse_from_attributes(&item.attrs)?;
57 let def = enums::EnumDef::new(&item.ident, meta, &item.variants)?;
58 let generics = GenericsInfo::bake(item.generics);
59 Ok((item.vis, item.ident, Box::new(def), generics))
60 }
61 other => Err(Error::new_spanned(other, "cannot derive on this item")),
62 }
63}
64
65fn from_xml_impl(input: Item) -> Result<TokenStream> {
68 let (vis, ident, def, mut generics) = parse_struct(input)?;
69
70 let name_ident = Ident::new("name", Span::call_site());
71 let attrs_ident = Ident::new("attrs", Span::call_site());
72
73 let FromXmlParts {
74 defs,
75 from_events_body,
76 builder_ty,
77 name_matcher,
78 } = def.make_from_events_builder(&vis, &mut generics, &name_ident, &attrs_ident)?;
79
80 let GenericsInfo {
81 decl: generics_decl,
82 ref_: generics_ref,
83 where_clause,
84 ..
85 } = generics;
86
87 #[cfg_attr(not(feature = "minidom"), allow(unused_mut))]
88 let mut result = quote! {
89 #defs
90
91 impl #generics_decl ::xso::FromXml for #ident #generics_ref #where_clause {
92 type Builder = #builder_ty;
93
94 fn from_events(
95 name: ::xso::exports::rxml::QName,
96 attrs: ::xso::exports::rxml::AttrMap,
97 ctx: &::xso::Context<'_>,
98 ) -> ::core::result::Result<Self::Builder, ::xso::error::FromEventsError> {
99 #from_events_body
100 }
101
102 fn xml_name_matcher() -> ::xso::fromxml::XmlNameMatcher<'static> {
103 #name_matcher
104 }
105 }
106 };
107
108 #[cfg(feature = "minidom")]
109 result.extend(quote! {
110 impl #generics_decl ::core::convert::TryFrom<::xso::exports::minidom::Element> for #ident #generics_ref #where_clause {
111 type Error = ::xso::error::FromElementError;
112
113 fn try_from(other: ::xso::exports::minidom::Element) -> ::core::result::Result<Self, ::xso::error::FromElementError> {
114 ::xso::try_from_element(other)
115 }
116 }
117 });
118
119 if def.debug() {
120 println!("{}", result);
121 }
122
123 Ok(result)
124}
125
126#[proc_macro_derive(FromXml, attributes(xml))]
130pub fn from_xml(input: RawTokenStream) -> RawTokenStream {
131 let item = syn::parse_macro_input!(input as Item);
134 match from_xml_impl(item) {
135 Ok(v) => v.into(),
136 Err(e) => e.into_compile_error().into(),
137 }
138}
139
140fn as_xml_impl(input: Item) -> Result<TokenStream> {
143 let (vis, ident, def, mut generics) = parse_struct(input)?;
144
145 let AsXmlParts {
146 defs,
147 as_xml_iter_body,
148 item_iter_ty_lifetime,
149 item_iter_ty,
150 } = def.make_as_xml_iter(&vis, &mut generics)?;
151
152 let GenericsInfo {
153 decl: generics_decl,
154 ref_: generics_ref,
155 where_clause,
156 ..
157 } = generics;
158
159 #[cfg_attr(not(feature = "minidom"), allow(unused_mut))]
160 let mut result = quote! {
161 #defs
162
163 impl #generics_decl ::xso::AsXml for #ident #generics_ref #where_clause {
164 type ItemIter<#item_iter_ty_lifetime> = #item_iter_ty
165 where Self: #item_iter_ty_lifetime;
166
167 fn as_xml_iter(&self) -> ::core::result::Result<Self::ItemIter<'_>, ::xso::error::Error> {
168 #as_xml_iter_body
169 }
170 }
171 };
172
173 #[cfg(all(feature = "minidom", feature = "panicking-into-impl"))]
174 result.extend(quote! {
175 impl #generics_decl ::core::convert::From<#ident #generics_ref> for ::xso::exports::minidom::Element #where_clause {
176 fn from(other: #ident #generics_ref) -> Self {
177 ::xso::transform(&other).expect("seamless conversion into minidom::Element")
178 }
179 }
180
181 impl #generics_decl ::core::convert::From<&#ident #generics_ref> for ::xso::exports::minidom::Element #where_clause {
182 fn from(other: &#ident #generics_ref) -> Self {
183 ::xso::transform(other).expect("seamless conversion into minidom::Element")
184 }
185 }
186 });
187
188 #[cfg(all(feature = "minidom", not(feature = "panicking-into-impl")))]
189 result.extend(quote! {
190 impl #generics_decl ::core::convert::TryFrom<#ident #generics_ref> for ::xso::exports::minidom::Element #where_clause {
191 type Error = ::xso::error::Error;
192
193 fn try_from(other: #ident #generics_ref) -> ::core::result::Result<Self, Self::Error> {
194 ::xso::transform(&other)
195 }
196 }
197 impl #generics_decl ::core::convert::TryFrom<&#ident #generics_ref> for ::xso::exports::minidom::Element #where_clause {
198 type Error = ::xso::error::Error;
199
200 fn try_from(other: &#ident #generics_ref) -> ::core::result::Result<Self, Self::Error> {
201 ::xso::transform(other)
202 }
203 }
204 });
205
206 if def.debug() {
207 println!("{}", result);
208 }
209
210 Ok(result)
211}
212
213#[proc_macro_derive(AsXml, attributes(xml))]
217pub fn as_xml(input: RawTokenStream) -> RawTokenStream {
218 let item = syn::parse_macro_input!(input as Item);
221 match as_xml_impl(item) {
222 Ok(v) => v.into(),
223 Err(e) => e.into_compile_error().into(),
224 }
225}