1extern crate proc_macro;
2
3use proc_macro2::{Ident, Span, TokenStream};
4use quote::{format_ident, quote};
5use syn::{parse_macro_input, Data, DeriveInput, Fields, GenericArgument, PathArguments, Type};
6
7#[proc_macro_derive(DisplayInnerSegment)]
8pub fn display_inner(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
9 let ast = syn::parse_macro_input!(input as DeriveInput);
10 let toks = generate_inner_display(&ast).unwrap_or_else(|err| err.to_compile_error());
11 toks.into()
12}
13
14#[proc_macro_derive(DisplayOuterSegment)]
15pub fn display_outer(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
16 let ast = syn::parse_macro_input!(input as DeriveInput);
17 let toks = generate_outer_display(&ast).unwrap_or_else(|err| err.to_compile_error());
18 toks.into()
19}
20
21#[proc_macro_derive(DisplayEdifact)]
22pub fn display_edifact(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
23 let ast = syn::parse_macro_input!(input as DeriveInput);
24 let toks = generate_edifact(&ast).unwrap_or_else(|err| err.to_compile_error());
25 toks.into()
26}
27
28#[proc_macro_derive(DisplayEdifactSg)]
29pub fn display_edifact_sg(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
30 let ast = syn::parse_macro_input!(input as DeriveInput);
31 let toks = generate_edifact_sg(&ast).unwrap_or_else(|err| err.to_compile_error());
32 toks.into()
33}
34
35fn generate_inner_display(ast: &DeriveInput) -> syn::Result<TokenStream> {
36 let name = &ast.ident;
37 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
38 let output = gen_types(ast);
39 Ok(quote! {
40 impl #impl_generics ::core::fmt::Display for #name #ty_generics #where_clause {
41 fn fmt<'x>(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
42 let mut str: Vec<String> = vec![];
43 #(#output)*
44 let joined = str.join(":");
45 let joined = joined.trim_end_matches(":");
46 write!(f, "{}", joined)
47 }
48 }
49 })
50}
51
52fn generate_outer_display(ast: &DeriveInput) -> syn::Result<TokenStream> {
53 let name = &ast.ident;
54 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
55 let output = gen_types(ast);
56 let s = format_ident!("{}", name).to_string().to_uppercase();
57 Ok(quote! {
58 impl #impl_generics ::core::fmt::Display for #name #ty_generics #where_clause {
59 fn fmt<'x>(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 let mut str: Vec<String> = vec![];
61 str.push(#s.to_string());
62 #(#output)*
63 let joined = str.join("+");
64 let joined = joined.trim_end_matches("+");
65 if joined.len() > 3 {
66 write!(f, "{}", joined)
67 }else{
68 write!(f, "")
69 }
70 }
71 }
72 })
73}
74
75fn generate_edifact(ast: &DeriveInput) -> syn::Result<TokenStream> {
76 let name = &ast.ident;
77 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
78 let output = gen_types(ast);
79 Ok(quote! {
80 impl #impl_generics ::core::fmt::Display for #name #ty_generics #where_clause {
81 fn fmt<'x>(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 let mut str: Vec<String> = vec![];
83 #(#output)*
84 let str: Vec<String> = str
86 .iter()
87 .map(|v| v.clone())
88 .filter(|s| !s.is_empty())
89 .collect();
90 let joined = str.join("'\n");
91 write!(f, "{}'", joined)
92 }
93 }
94 })
95}
96
97fn generate_edifact_sg(ast: &DeriveInput) -> syn::Result<TokenStream> {
98 let name = &ast.ident;
99 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
100 let output = gen_types(ast);
101 Ok(quote! {
102 impl #impl_generics ::core::fmt::Display for #name #ty_generics #where_clause {
103 fn fmt<'x>(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 let mut str: Vec<String> = vec![];
105 #(#output)*
106 let str: Vec<String> = str
108 .iter()
109 .map(|v| v.clone())
110 .filter(|s| !s.is_empty())
111 .collect();
112 let joined = str.join("'\n");
113 write!(f, "{}", joined)
114 }
115 }
116 })
117}
118
119fn gen_types(ast: &DeriveInput) -> Vec<TokenStream> {
120 let x = &ast.data;
121 let mut output = vec![];
122 if let Data::Struct(s) = x {
123 let f = &s.fields;
124 for o in f {
125 let id = o.ident.clone().unwrap();
126 let t = &o.ty;
127 if let syn::Type::Path(p) = t {
128 let s = &p.path.segments;
129 let w = &s.first().unwrap().ident;
130 let ty = w.to_string();
131 match ty.as_str() {
132 "Vec" => {
133 let ts = quote! {
134 if self.#id.is_empty() {
135 str.push("".to_string());
136 }else{
137 self.#id.iter().for_each(|x| str.push(format!("{}",x)));
138 }
139 };
140 output.push(ts);
141 }
142 "Option" => {
143 let ts = quote! {
144 str.push(self.#id.as_ref().map_or("".to_string(),|x| format!("{}",x)));
145 };
146 output.push(ts);
147 }
148 _ => {
149 let ts = quote! {
150 str.push(format!("{}",self.#id));
151 };
152 output.push(ts);
153 }
154 }
155 }
156 }
157 }
158 output
159}
160
161#[proc_macro_derive(ParseInnerSegment)]
162pub fn parse_inner(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
163 let ast = syn::parse_macro_input!(input as DeriveInput);
164 let toks = generate_inner_parse(&ast).unwrap_or_else(|err| err.to_compile_error());
165 toks.into()
166}
167
168fn generate_inner_parse(ast: &DeriveInput) -> syn::Result<TokenStream> {
169 let name = &ast.ident;
170 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
171 let output = gen_inner_props(ast);
172 let prop_count = output.len();
173 Ok(quote! {
174 impl #impl_generics ::core::str::FromStr for #name #ty_generics #where_clause {
175 type Err = ParseError;
176
177 fn from_str(s: &str) -> Result<Self, Self::Err> {
178 let parts: Vec<&str> = s.split(':').collect();
179 if parts.len() > #prop_count {
180 Err(ParseError {
181 msg: "too many segments".to_string(),
182 })
183 } else {
184 Ok(#name {
185 #(#output)*
186 })
187 }
188 }
189 }
190 })
191}
192
193fn gen_inner_props(ast: &DeriveInput) -> Vec<TokenStream> {
194 let x = &ast.data;
195 let mut output = vec![];
196 let mut idx: usize = 0;
197 if let Data::Struct(s) = x {
198 let f = &s.fields;
199 for o in f {
200 let id = o.ident.clone().unwrap();
201 let t = &o.ty;
202 if let syn::Type::Path(p) = t {
203 let s = &p.path.segments;
204 let w = &s.first().unwrap().ident;
205 let ty = w.to_string();
206 match ty.as_str() {
207 "Option" => {
208 let chunk = quote! {
209 #id: parts.get(#idx).map(|x| x.to_string()),
210 };
211 output.push(chunk);
212 }
213 _ => {
214 let chunk = quote! {
215 #id: parts.get(#idx).map(|x| x.to_string()).unwrap_or_default(),
216 };
217 output.push(chunk);
218 }
219 }
220 }
221 idx += 1;
222 }
223 }
224 output
225}
226
227#[proc_macro_derive(ParseElement)]
228pub fn parse_element(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
229 let input = parse_macro_input!(input as DeriveInput);
230 let output = generate_element_parser(&input).unwrap_or_else(|err| err.to_compile_error());
231 #[cfg(feature = "debug")]
232 println!("{output}");
233 proc_macro::TokenStream::from(output)
234}
235
236fn generate_element_parser(ast: &DeriveInput) -> syn::Result<TokenStream> {
237 let name = &ast.ident;
238 let tok = parse_all(ast);
239 let s = format_ident!("{}", name).to_string().to_uppercase();
240 let res = quote! {
241 impl<'a> crate::util::Parser<&'a str, #name, nom::error::Error<&'a str>> for #name {
242 fn parse(input: &'a str) -> ::nom::IResult<&'a str, #name> {
243 #[cfg(feature = "logging")]
244 log::debug!("Parser is inside {}", #s);
245 let (_, vars) = crate::util::parse_colon_section(input)?;
246 #[cfg(feature = "logging")]
247 log::debug!("Variables created {vars:?}");
248 let output = #name {
249 #(#tok)*
250 };
251 Ok(("", output))
252 }
253 }
254 };
255 Ok(res)
256}
257
258#[proc_macro_derive(ParseSg)]
259pub fn parse_sg(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
260 let input = parse_macro_input!(input as DeriveInput);
261 let output = generate_sg_parser(&input, true).unwrap_or_else(|err| err.to_compile_error());
262 proc_macro::TokenStream::from(output)
263}
264
265#[proc_macro_derive(ParseMsg)]
266pub fn parse_msg(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
267 let input = parse_macro_input!(input as DeriveInput);
268 let output = generate_sg_parser(&input, false).unwrap_or_else(|err| err.to_compile_error());
269 #[cfg(feature = "debug")]
270 println!("{output}");
271 proc_macro::TokenStream::from(output)
272}
273
274fn generate_sg_parser(ast: &DeriveInput, is_sg: bool) -> syn::Result<TokenStream> {
275 let name = &ast.ident;
276 let mut lefties = vec![];
277 let mut attries = vec![];
278 if let Data::Struct(left_vec) = &ast.data {
279 if let Fields::Named(f) = &left_vec.fields {
280 for (idx, ff) in (&f.named).into_iter().enumerate() {
281 let left = match &ff.ident {
282 Some(l) => l.clone(),
283 None => Ident::new("", Span::call_site()),
284 };
285
286 let all = if let Type::Path(tyty) = &ff.ty {
289 let inside = &tyty.path.segments[0];
290 let inside_str = inside.ident.to_string();
291 match inside_str.as_str() {
293 "Vec" | "Option" => {
294 if let PathArguments::AngleBracketed(inside_optvec) = &inside.arguments
295 {
296 if let GenericArgument::Type(Type::Path(t)) = &inside_optvec.args[0]
297 {
298 let ti = &t.path.segments[0].ident;
299 (
300 quote! {
301 #left
302 },
303 if inside_str == "Vec" {
304 if !is_sg || idx != 0 {
307 quote! {
308 let (outer_rest, #left) = nom::multi::many0(#ti::parse).parse(outer_rest)?;
310 }
311 } else {
312 quote! {
313 let (outer_rest, #left) = nom::multi::many1(#ti::parse).parse(outer_rest)?;
314 }
315 }
316 } else {
317 quote! {
318 let (outer_rest, #left) = nom::combinator::opt(#ti::parse).parse(outer_rest)?;
319 }
320 },
321 )
322 } else {
323 (quote! {}, quote! {})
324 }
325 } else {
326 (quote! {}, quote! {})
327 }
328 }
329 _ => {
330 let i = inside.ident.clone();
331 (
332 quote! {
333 #left
334 },
335 quote! {
336 let (outer_rest, #left) = #i::parse(outer_rest)?;
338 },
339 )
340 }
341 }
342 } else {
343 (quote! {}, quote! {})
344 };
345 lefties.push(all.0);
346 attries.push(all.1);
347 }
348 }
349 };
350 let s = format_ident!("{}", name).to_string().to_uppercase();
351 let res = quote! {
352 impl<'a> crate::util::Parser<&'a str, #name, nom::error::Error<&'a str>> for #name {
360 fn parse(input: &'a str) -> ::nom::IResult<&'a str, #name> {
361 #[cfg(feature = "logging")]
362 log::debug!("Parser is inside {}", #s);
363 let outer_rest = input;
364 #(#attries)*
365 Ok((outer_rest, #name { #(#lefties),* }))
366 }
367 }
368 };
369 #[cfg(feature = "debug")]
370 println!("{res}");
371 Ok(res)
372}
373
374#[proc_macro_derive(ParseSegment)]
388pub fn parse_segment(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
389 let input = parse_macro_input!(input as DeriveInput);
390 let output = generate_segment_parser(&input).unwrap_or_else(|err| err.to_compile_error());
391 #[cfg(feature = "debug")]
392 println!("{output}");
393 proc_macro::TokenStream::from(output)
394}
395
396fn generate_segment_parser(ast: &DeriveInput) -> syn::Result<TokenStream> {
407 let name = &ast.ident;
408 let tok = parse_all(ast);
409 let s = format_ident!("{}", name).to_string().to_uppercase();
410 let res = quote! {
411 impl<'a> crate::util::Parser<&'a str, #name, nom::error::Error<&'a str>> for #name {
412 fn parse(input: &'a str) -> ::nom::IResult<&'a str, #name> {
413 #[cfg(feature = "logging")]
414 log::debug!("Parser is inside {}", #s);
415 let (output_rest, vars) = crate::util::parse_line(input, #s)?;
416 #[cfg(feature = "logging")]
417 log::debug!("Variables created {vars:?}");
418 #[cfg(feature = "logging")]
419 log::debug!("Left over string {output_rest:?}");
420 let output = #name {
421 #(#tok)*
422 };
423 Ok((output_rest, output))
424 }
425 }
426 };
427 Ok(res)
428}
429
430fn parse_all(ast: &DeriveInput) -> Vec<TokenStream> {
431 let x = &ast.data;
432 let name = format!("{}", &ast.ident);
433 let mut output = vec![];
434 if let Data::Struct(s) = x {
435 let f = &s.fields;
436 for (idx, o) in f.into_iter().enumerate() {
437 let struct_field = o.ident.clone().unwrap();
439 let sf_string = struct_field.to_string();
440 let syn::Type::Path(tp) = &o.ty else {
441 panic!("Path type not found!")
442 };
443 let s = tp.path.segments.first().unwrap();
444 let opt_vec = s.ident.clone();
445 let ov_string = opt_vec.to_string();
446 match opt_vec.to_string().as_str() {
447 "Option" | "Vec" => {
448 let mut inside_opt_vec: Ident = Ident::new("placeholder", Span::call_site());
450 if let PathArguments::AngleBracketed(abga) = &s.arguments {
451 if let GenericArgument::Type(syn::Type::Path(tp)) =
452 abga.args.first().unwrap()
453 {
454 inside_opt_vec = tp.path.segments.first().unwrap().ident.clone();
455 }
456 }
457 let iov_string = inside_opt_vec.to_string();
458
459 if inside_opt_vec == "String" {
461 output.push(quote! {
462 #struct_field: vars.get(#idx).map(|x| x.to_string()),
463 });
464 } else if inside_opt_vec.to_string().starts_with('_') {
465 output.push(quote! {
467 #struct_field: vars.get(#idx).filter(|&f| !f.is_empty()).map(|x| match #inside_opt_vec::from_str(clean_num(x)) {
468 Ok(f) => f,
469 Err(e) => {
470 #[cfg(feature = "logging")]
471 log::error!("Line: {input}\nFor struct {}, parsing optional list item {} failed. Enum {} encountered the following error: {}", #name, #sf_string, #iov_string, e);
472 panic!("Parsing optional list item failed");
473 },
474 }),
475 });
476 } else {
477 output.push(quote! {
479 #struct_field: vars.get(#idx).filter(|&f| !f.is_empty()).map(|x| match #inside_opt_vec::parse(x) {
480 Ok((_,r)) => r,
481 Err(e) => {
482 #[cfg(feature = "logging")]
483 log::error!("Line: {input}\nFor struct {}, parsing optional segment or element {} failed. Struct {} encountered the following error: {}", #name, #sf_string, #iov_string, e);
484 panic!("Parsing optional segment or element failed");
485 },
486 }),
487 });
488 }
489 }
490 "String" => {
491 output.push(quote! {
492 #struct_field: match vars.get(#idx).filter(|&f| !f.is_empty()).map(|x| x.to_string()) {
493 Some(f) => f,
494 None => {
495 #[cfg(feature = "logging")]
496 log::error!("Line: {input}\nFor struct {}, parsing mandatory {}.to_string() was not found", #name, #sf_string);
497 panic!("Parsing mandatory to_string() failed");
498 },
499 },
500 });
501 }
502 _ => {
503 if opt_vec.to_string().starts_with('_') {
505 output.push(quote! {
507 #struct_field: vars.get(#idx).filter(|&f| !f.is_empty()).map(|x|match #opt_vec::from_str(clean_num(x)){
508 Ok(f) => f,
509 Err(e) => {
510 #[cfg(feature = "logging")]
511 log::error!("Line: {input}\nFor struct {}, parsing list item {} failed. Enum {} encountered the following error: {}", #name, #sf_string, #ov_string, e);
512 panic!("Parsing list item failed");
513 },
514 }).expect("Parsing List: not found"),
515 });
516 } else {
517 output.push(quote! {
519 #struct_field: vars.get(#idx).filter(|&f| !f.is_empty()).map(|x| match #opt_vec::parse(x) {
520 Ok((_,r)) => r,
521 Err(e) => {
522 #[cfg(feature = "logging")]
523 log::error!("Line: {input}\nFor struct {}, parsing segment or element {} failed. Struct {} encountered the following error: {}", #name, #sf_string, #ov_string, e);
524 panic!("Parsing list item failed");
525 },
526 }).expect("Parsing Segement or Element: not found"),
527 });
528 }
529 }
530 }
531 }
532 }
533 output
534}
535
536#[proc_macro_derive(ParseOuterSegment)]
537pub fn parse_outer(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
538 let ast = syn::parse_macro_input!(input as DeriveInput);
539 let toks = generate_outer_parse(&ast).unwrap_or_else(|err| err.to_compile_error());
540 toks.into()
541}
542
543fn generate_outer_parse(ast: &DeriveInput) -> syn::Result<TokenStream> {
544 let name = &ast.ident;
545 let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
546 let output = gen_outer_props(ast);
547 let prop_count = output.len();
548 let upper_name = format_ident!("{}", name).to_string().to_uppercase();
549 Ok(quote! {
550 impl #impl_generics ::core::str::FromStr for #name #ty_generics #where_clause {
551 type Err = ParseError;
552
553 fn from_str(s: &str) -> Result<Self, Self::Err> {
554 let x = s.trim_end_matches('\'');
555 let parts: Vec<&str> = x.split('+').collect();
556 if parts[0] == #upper_name {
557 if parts.len() > #prop_count +1 {
558 Err(ParseError {
559 msg: "too many segments".to_string(),
560 })
561 } else {
562 let mut obj = #name::default();
563 #(#output)*
564 Ok(obj)
565 }
566 } else {
567 Err(ParseError {
568 msg: "segment name wrong".to_string(),
569 })
570 }
571 }
572 }
573 })
574}
575
576fn gen_outer_props(ast: &DeriveInput) -> Vec<TokenStream> {
577 let x = &ast.data;
578 let mut output = vec![];
579 let mut idx: usize = 1;
580 if let Data::Struct(s) = x {
581 let f = &s.fields;
582 for o in f {
583 let id = o.ident.clone().unwrap();
584 let t = &o.ty;
585 if let syn::Type::Path(p) = t {
586 let s = &p.path.segments;
587 let we = s.first().unwrap();
588 let w = &we.ident;
589 let arg = &we.arguments;
590 let sub_id = &we.ident;
591 let ty = w.to_string();
592 match ty.as_str() {
593 "Option" => {
594 if let PathArguments::AngleBracketed(c) = arg {
596 let o = c.args.first().unwrap();
597 if let syn::GenericArgument::Type(syn::Type::Path(tpo)) = o {
598 let sg = tpo.path.segments.first().unwrap();
599 let ident = &sg.ident;
600 let type_name = ident.to_string();
601 match type_name.as_str() {
602 "String" => {
603 let chunk = quote! {
604 if let Some(val) = parts.get(#idx) {
605 obj.#id = Some(val.to_string());
606 }
607 };
608 output.push(chunk);
609 }
610 _ => {
611 let chunk = quote! {
612 if let Some(val) = parts.get(#idx) {
613 let t = #ident::from_str(val).unwrap();
614 obj.#id = Some(t);
615 }
616 };
617 output.push(chunk);
618 }
619 }
620 }
621 }
622 }
623 "String" => {
624 let chunk = quote! {
625 if let Some(val) = parts.get(#idx) {
626 obj.#id = val.to_string();
627 }
628 };
629 output.push(chunk);
630 }
631 _ => {
632 let chunk = quote! {
633 if let Some(val) = parts.get(#idx) {
634 obj.#id = #sub_id::from_str(val).unwrap();
635 }
636 };
637 output.push(chunk);
638 }
639 }
640 }
641 idx += 1;
642 }
643 }
644 output
645}