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