1use proc_macro::TokenStream;
66use proc_macro2::TokenStream as TokenStream2;
67use quote::quote;
68use syn::{Data, DeriveInput, Field, Fields, Type, parse_macro_input, spanned::Spanned};
69
70#[proc_macro_derive(EdifactSerialize, attributes(edifact))]
73pub fn derive_edifact_serialize(input: TokenStream) -> TokenStream {
82 let input = parse_macro_input!(input as DeriveInput);
83 impl_serialize(&input)
84 .unwrap_or_else(|e| e.to_compile_error())
85 .into()
86}
87
88#[proc_macro_derive(EdifactDeserialize, attributes(edifact))]
89pub fn derive_edifact_deserialize(input: TokenStream) -> TokenStream {
98 let input = parse_macro_input!(input as DeriveInput);
99 impl_deserialize(&input)
100 .unwrap_or_else(|e| e.to_compile_error())
101 .into()
102}
103
104#[derive(Default)]
107struct StructAttrs {
108 segment: Option<String>,
110 qualifier: Option<String>,
112 qualifier_span: Option<proc_macro2::Span>,
113 qualifier_from: Option<u32>,
115 qualifier_from_span: Option<proc_macro2::Span>,
116}
117
118#[derive(Default)]
119struct FieldAttrs {
120 element: Option<u32>,
122 element_span: Option<proc_macro2::Span>,
123 component: Option<u32>,
125 component_span: Option<proc_macro2::Span>,
126 composite: bool,
128 composite_span: Option<proc_macro2::Span>,
129 group: bool,
131 group_span: Option<proc_macro2::Span>,
132 qualifier: Option<String>,
134 qualifier_span: Option<proc_macro2::Span>,
135}
136
137fn parse_struct_attrs(input: &DeriveInput) -> syn::Result<StructAttrs> {
140 let mut out = StructAttrs::default();
141 for attr in &input.attrs {
142 if !attr.path().is_ident("edifact") {
143 continue;
144 }
145 attr.parse_nested_meta(|meta| {
146 if meta.path.is_ident("segment") {
147 let lit = meta.value()?.parse::<syn::LitStr>()?;
148 let tag = lit.value();
149 if tag.len() != 3 || !tag.bytes().all(|b| b.is_ascii_uppercase()) {
150 return Err(syn::Error::new(
151 lit.span(),
152 format!(
153 "segment tag must be exactly 3 ASCII uppercase letters; got {tag:?}"
154 ),
155 ));
156 }
157 out.segment = Some(tag);
158 } else if meta.path.is_ident("qualifier") {
159 out.qualifier = Some(meta.value()?.parse::<syn::LitStr>()?.value());
160 out.qualifier_span = Some(meta.path.span());
161 } else if meta.path.is_ident("qualifier_from") {
162 let idx: u32 = meta.value()?.parse::<syn::LitInt>()?.base10_parse()?;
163 out.qualifier_from = Some(idx);
164 out.qualifier_from_span = Some(meta.path.span());
165 } else {
166 return Err(meta.error("unknown struct-level `edifact` key; expected `segment`, `qualifier`, or `qualifier_from`"));
167 }
168 Ok(())
169 })?;
170 }
171 if (out.qualifier.is_some() || out.qualifier_from.is_some()) && out.segment.is_none() {
172 return Err(syn::Error::new(
173 out.qualifier_span
174 .or(out.qualifier_from_span)
175 .unwrap_or_else(|| input.span()),
176 "#[edifact(qualifier = ...)] / #[edifact(qualifier_from = ...)] require #[edifact(segment = ...)]",
177 ));
178 }
179 if out.qualifier.is_some() && out.qualifier_from.is_some() {
180 return Err(syn::Error::new(
181 out.qualifier_from_span
182 .or(out.qualifier_span)
183 .unwrap_or_else(|| input.span()),
184 "use either #[edifact(qualifier = ...)] or #[edifact(qualifier_from = ...)], not both",
185 ));
186 }
187 Ok(out)
188}
189
190fn parse_field_attrs(field: &Field) -> syn::Result<FieldAttrs> {
191 let mut out = FieldAttrs::default();
192 for attr in &field.attrs {
193 if !attr.path().is_ident("edifact") {
194 continue;
195 }
196 attr.parse_nested_meta(|meta| {
197 if meta.path.is_ident("element") {
198 out.element = Some(meta.value()?.parse::<syn::LitInt>()?.base10_parse()?);
199 out.element_span = Some(meta.path.span());
200 } else if meta.path.is_ident("component") {
201 out.component = Some(meta.value()?.parse::<syn::LitInt>()?.base10_parse()?);
202 out.component_span = Some(meta.path.span());
203 } else if meta.path.is_ident("composite") {
204 out.composite = true;
205 out.composite_span = Some(meta.path.span());
206 } else if meta.path.is_ident("group") {
207 out.group = true;
208 out.group_span = Some(meta.path.span());
209 } else if meta.path.is_ident("qualifier") {
210 out.qualifier = Some(meta.value()?.parse::<syn::LitStr>()?.value());
211 out.qualifier_span = Some(meta.path.span());
212 } else {
213 return Err(meta.error("unknown field-level `edifact` key; expected `element`, `component`, `composite`, `group`, or `qualifier`"));
214 }
215 Ok(())
216 })?;
217 }
218 Ok(out)
219}
220
221fn is_option_type(ty: &Type) -> bool {
224 matches!(ty, Type::Path(p) if p.path.segments.last().is_some_and(|s| s.ident == "Option"))
225}
226
227fn is_vec_type(ty: &Type) -> bool {
228 matches!(ty, Type::Path(p) if p.path.segments.last().is_some_and(|s| s.ident == "Vec"))
229}
230
231fn is_string_type(ty: &Type) -> bool {
233 matches!(ty, Type::Path(p) if p.path.is_ident("String")
234 || p.path.segments.last().is_some_and(|s| s.ident == "String"))
235}
236
237fn is_str_ref_type(ty: &Type) -> bool {
239 let Type::Reference(r) = ty else { return false };
240 matches!(r.elem.as_ref(), Type::Path(p) if p.path.is_ident("str"))
241}
242
243fn is_str_like(ty: &Type) -> bool {
246 is_string_type(ty) || is_str_ref_type(ty)
247}
248
249fn option_inner_type(ty: &Type) -> Option<&Type> {
250 let Type::Path(path) = ty else { return None };
251 let seg = path.path.segments.last()?;
252 if seg.ident != "Option" {
253 return None;
254 }
255 let syn::PathArguments::AngleBracketed(args) = &seg.arguments else {
256 return None;
257 };
258 let syn::GenericArgument::Type(inner) = args.args.first()? else {
259 return None;
260 };
261 Some(inner)
262}
263
264fn vec_inner_type(ty: &Type) -> Option<&Type> {
265 let Type::Path(path) = ty else { return None };
266 let seg = path.path.segments.last()?;
267 if seg.ident != "Vec" {
268 return None;
269 }
270 let syn::PathArguments::AngleBracketed(args) = &seg.arguments else {
271 return None;
272 };
273 let syn::GenericArgument::Type(inner) = args.args.first()? else {
274 return None;
275 };
276 Some(inner)
277}
278
279fn get_named_fields(input: &DeriveInput) -> syn::Result<&syn::FieldsNamed> {
282 if !input.generics.params.is_empty() {
283 return Err(syn::Error::new(
284 input.generics.params.span(),
285 "EdifactSerialize/EdifactDeserialize do not support generic structs",
286 ));
287 }
288 match &input.data {
289 Data::Struct(s) => match &s.fields {
290 Fields::Named(f) => Ok(f),
291 _ => Err(syn::Error::new(
292 input.span(),
293 "EdifactSerialize/EdifactDeserialize only support structs with named fields",
294 )),
295 },
296 _ => Err(syn::Error::new(
297 input.span(),
298 "EdifactSerialize/EdifactDeserialize only support structs",
299 )),
300 }
301}
302
303fn validate_field_attrs(
304 ident: &syn::Ident,
305 ty: &Type,
306 attrs: &FieldAttrs,
307 is_segment_struct: bool,
308) -> syn::Result<()> {
309 if attrs.group && !is_vec_type(ty) {
310 return Err(syn::Error::new(
311 attrs.group_span.unwrap_or_else(|| ident.span()),
312 format!("field `{ident}`: #[edifact(group)] requires Vec<T>"),
313 ));
314 }
315 if attrs.group && (attrs.element.is_some() || attrs.component.is_some()) {
316 return Err(syn::Error::new(
317 attrs.group_span.unwrap_or_else(|| ident.span()),
318 format!(
319 "field `{ident}`: #[edifact(group)] cannot be combined with element/component positioning"
320 ),
321 ));
322 }
323 if attrs.composite && attrs.component.is_some() {
324 return Err(syn::Error::new(
325 attrs.component_span.unwrap_or_else(|| ident.span()),
326 format!(
327 "field `{ident}`: #[edifact(component = ...)] cannot be combined with #[edifact(composite)]"
328 ),
329 ));
330 }
331 if attrs.composite && attrs.group {
332 return Err(syn::Error::new(
333 attrs.composite_span.unwrap_or_else(|| ident.span()),
334 format!(
335 "field `{ident}`: #[edifact(composite)] cannot be combined with #[edifact(group)]"
336 ),
337 ));
338 }
339 if is_segment_struct && attrs.group {
340 return Err(syn::Error::new(
341 attrs.group_span.unwrap_or_else(|| ident.span()),
342 format!("field `{ident}`: #[edifact(group)] is only valid on message structs"),
343 ));
344 }
345 if !is_segment_struct && (attrs.element.is_some() || attrs.component.is_some()) {
346 return Err(syn::Error::new(
347 attrs
348 .element_span
349 .or(attrs.component_span)
350 .unwrap_or_else(|| ident.span()),
351 format!(
352 "field `{ident}`: element/component positioning is only valid on segment structs"
353 ),
354 ));
355 }
356 if !is_segment_struct && attrs.composite {
357 return Err(syn::Error::new(
358 attrs.composite_span.unwrap_or_else(|| ident.span()),
359 format!("field `{ident}`: #[edifact(composite)] is only valid on segment structs"),
360 ));
361 }
362 if is_segment_struct && attrs.qualifier.is_some() {
363 return Err(syn::Error::new(
364 attrs.qualifier_span.unwrap_or_else(|| ident.span()),
365 format!(
366 "field `{ident}`: #[edifact(qualifier = ...)] is only valid on message struct fields"
367 ),
368 ));
369 }
370 if attrs.qualifier.is_some() && attrs.group && !is_vec_type(ty) {
371 return Err(syn::Error::new(
372 attrs.qualifier_span.unwrap_or_else(|| ident.span()),
373 format!("field `{ident}`: qualifier-constrained groups must be Vec<T>"),
374 ));
375 }
376 Ok(())
377}
378
379fn impl_serialize(input: &DeriveInput) -> syn::Result<TokenStream2> {
382 let name = &input.ident;
383 let struct_attrs = parse_struct_attrs(input)?;
384 let fields = get_named_fields(input)?;
385 let is_segment_struct = struct_attrs.segment.is_some();
386
387 let field_data: Vec<(&syn::Ident, &Type, FieldAttrs)> = fields
389 .named
390 .iter()
391 .map(|f| {
392 let attrs = parse_field_attrs(f)?;
393 let ident = f
394 .ident
395 .as_ref()
396 .ok_or_else(|| syn::Error::new_spanned(f, "only named fields are supported"))?;
397 validate_field_attrs(ident, &f.ty, &attrs, is_segment_struct)?;
398 Ok((ident, &f.ty, attrs))
399 })
400 .collect::<syn::Result<_>>()?;
401
402 let body = if let Some(seg_tag) = &struct_attrs.segment {
403 let (qualifier_emit, start_slot, elem0_comp_stmts) = if let Some(qual) =
408 &struct_attrs.qualifier
409 {
410 for (i, (ident, _, attrs)) in field_data.iter().enumerate() {
412 let elem = attrs.element.unwrap_or(i as u32);
413 let comp = attrs.component.unwrap_or(0);
414 if elem == 0 && comp == 0 {
415 return Err(syn::Error::new(
416 attrs
417 .element_span
418 .or(attrs.component_span)
419 .unwrap_or_else(|| ident.span()),
420 format!(
421 "field `{}`: cannot use #[edifact(qualifier = ...)] with a field at element = 0 without component >= 1; the qualifier occupies component 0",
422 ident
423 ),
424 ));
425 }
426 }
427 let mut comp_fields: Vec<(u32, usize)> = field_data
429 .iter()
430 .enumerate()
431 .filter_map(|(i, (_, _, attrs))| {
432 let elem = attrs.element.unwrap_or(i as u32);
433 let comp = attrs.component.unwrap_or(0);
434 if elem == 0 && comp > 0 {
435 Some((comp, i))
436 } else {
437 None
438 }
439 })
440 .collect();
441 comp_fields.sort_by_key(|(c, _)| *c);
442 let comp_stmts: Vec<TokenStream2> = comp_fields
443 .iter()
444 .map(|(_, fi)| {
445 let (ident, ty, _) = &field_data[*fi];
446 emit_component_element(ident, ty)
447 })
448 .collect();
449 let q = quote! {
450 emitter.emit(::edifact_rs::EdifactEvent::Element { value: #qual })?;
451 };
452 (q, 1u32, quote! { #(#comp_stmts)* })
453 } else {
454 (quote! {}, 0u32, quote! {})
455 };
456
457 let regular_field_data: Vec<(u32, usize)> = field_data
459 .iter()
460 .enumerate()
461 .filter_map(|(i, (_, _, attrs))| {
462 let elem = attrs.element.unwrap_or(i as u32);
463 if elem < start_slot {
464 None
465 } else {
466 Some((elem, i))
467 }
468 })
469 .collect();
470 let reg_max_idx = regular_field_data
471 .iter()
472 .map(|(e, _)| *e)
473 .max()
474 .unwrap_or(start_slot.saturating_sub(1));
475 let reg_field_map: std::collections::HashMap<u32, usize> =
476 regular_field_data.iter().copied().collect();
477
478 let mut elem_stmts: Vec<TokenStream2> = Vec::new();
479 for slot in start_slot..=reg_max_idx {
480 if let Some(&fi) = reg_field_map.get(&slot) {
481 let (ident, ty, attrs) = &field_data[fi];
482 if attrs.composite {
483 elem_stmts.push(emit_composite_field(ident, ty));
484 } else {
485 elem_stmts.push(emit_element(ident, ty));
486 }
487 } else {
488 elem_stmts.push(quote! {
490 emitter.emit(::edifact_rs::EdifactEvent::Element { value: "" })?;
491 });
492 }
493 }
494
495 quote! {
496 emitter.emit(::edifact_rs::EdifactEvent::StartSegment { tag: #seg_tag })?;
497 #qualifier_emit
498 #elem0_comp_stmts
499 #(#elem_stmts)*
500 emitter.emit(::edifact_rs::EdifactEvent::EndSegment)?;
501 }
502 } else {
503 let stmts: Vec<TokenStream2> = field_data
505 .iter()
506 .map(|(ident, ty, attrs)| {
507 if attrs.group || is_vec_type(ty) {
508 quote! {
509 for __item in &self.#ident {
510 ::edifact_rs::EdifactSerialize::edifact_serialize(__item, emitter)?;
511 }
512 }
513 } else {
514 quote! {
515 ::edifact_rs::EdifactSerialize::edifact_serialize(&self.#ident, emitter)?;
516 }
517 }
518 })
519 .collect();
520 quote! { #(#stmts)* }
521 };
522
523 Ok(quote! {
524 impl ::edifact_rs::EdifactSerialize for #name {
525 fn edifact_serialize<__E: ::edifact_rs::EventEmitter>(
526 &self,
527 emitter: &mut __E,
528 ) -> ::core::result::Result<(), ::edifact_rs::EdifactError> {
529 #body
530 ::core::result::Result::Ok(())
531 }
532 }
533 })
534}
535
536fn emit_element(ident: &syn::Ident, ty: &Type) -> TokenStream2 {
541 if is_option_type(ty) {
542 let inner_is_str = option_inner_type(ty).is_some_and(is_str_like);
543 if inner_is_str {
544 quote! {
545 match &self.#ident {
546 ::core::option::Option::Some(__v) => {
547 emitter.emit(::edifact_rs::EdifactEvent::Element { value: __v.as_str() })?;
548 }
549 ::core::option::Option::None => {
550 emitter.emit(::edifact_rs::EdifactEvent::Element { value: "" })?;
551 }
552 }
553 }
554 } else {
555 quote! {
556 match &self.#ident {
557 ::core::option::Option::Some(__v) => {
558 let __s = ::std::string::ToString::to_string(__v);
559 emitter.emit(::edifact_rs::EdifactEvent::Element { value: &__s })?;
560 }
561 ::core::option::Option::None => {
562 emitter.emit(::edifact_rs::EdifactEvent::Element { value: "" })?;
563 }
564 }
565 }
566 }
567 } else if is_string_type(ty) {
568 quote! {
569 emitter.emit(::edifact_rs::EdifactEvent::Element { value: self.#ident.as_str() })?;
570 }
571 } else if is_str_ref_type(ty) {
572 quote! {
573 emitter.emit(::edifact_rs::EdifactEvent::Element { value: self.#ident })?;
574 }
575 } else {
576 quote! {
577 {
578 let __s = ::std::string::ToString::to_string(&self.#ident);
579 emitter.emit(::edifact_rs::EdifactEvent::Element { value: &__s })?;
580 }
581 }
582 }
583}
584
585fn emit_component_element(ident: &syn::Ident, ty: &Type) -> TokenStream2 {
589 if is_option_type(ty) {
590 let inner_is_str = option_inner_type(ty).is_some_and(is_str_like);
591 if inner_is_str {
592 quote! {
593 match &self.#ident {
594 ::core::option::Option::Some(__v) => {
595 emitter.emit(::edifact_rs::EdifactEvent::ComponentElement { value: __v.as_str() })?;
596 }
597 ::core::option::Option::None => {
598 emitter.emit(::edifact_rs::EdifactEvent::ComponentElement { value: "" })?;
599 }
600 }
601 }
602 } else {
603 quote! {
604 match &self.#ident {
605 ::core::option::Option::Some(__v) => {
606 let __s = ::std::string::ToString::to_string(__v);
607 emitter.emit(::edifact_rs::EdifactEvent::ComponentElement { value: &__s })?;
608 }
609 ::core::option::Option::None => {
610 emitter.emit(::edifact_rs::EdifactEvent::ComponentElement { value: "" })?;
611 }
612 }
613 }
614 }
615 } else if is_string_type(ty) {
616 quote! {
617 emitter.emit(::edifact_rs::EdifactEvent::ComponentElement { value: self.#ident.as_str() })?;
618 }
619 } else if is_str_ref_type(ty) {
620 quote! {
621 emitter.emit(::edifact_rs::EdifactEvent::ComponentElement { value: self.#ident })?;
622 }
623 } else {
624 quote! {
625 {
626 let __s = ::std::string::ToString::to_string(&self.#ident);
627 emitter.emit(::edifact_rs::EdifactEvent::ComponentElement { value: &__s })?;
628 }
629 }
630 }
631}
632
633fn emit_composite_field(ident: &syn::Ident, ty: &Type) -> TokenStream2 {
635 if is_option_type(ty) {
636 quote! {
637 match &self.#ident {
638 ::core::option::Option::Some(__v) => {
639 ::edifact_rs::EdifactCompositeSerialize::edifact_serialize_composite(__v, emitter)?;
640 }
641 ::core::option::Option::None => {
642 emitter.emit(::edifact_rs::EdifactEvent::Element { value: "" })?;
643 }
644 }
645 }
646 } else {
647 quote! {
648 ::edifact_rs::EdifactCompositeSerialize::edifact_serialize_composite(&self.#ident, emitter)?;
649 }
650 }
651}
652
653fn impl_deserialize(input: &DeriveInput) -> syn::Result<TokenStream2> {
656 let name = &input.ident;
657 let struct_attrs = parse_struct_attrs(input)?;
658 let fields = get_named_fields(input)?;
659 let is_segment_struct = struct_attrs.segment.is_some();
660
661 let field_data: Vec<(&syn::Ident, &Type, FieldAttrs)> = fields
662 .named
663 .iter()
664 .map(|f| {
665 let attrs = parse_field_attrs(f)?;
666 let ident = f
667 .ident
668 .as_ref()
669 .ok_or_else(|| syn::Error::new_spanned(f, "only named fields are supported"))?;
670 validate_field_attrs(ident, &f.ty, &attrs, is_segment_struct)?;
671 Ok((ident, &f.ty, attrs))
672 })
673 .collect::<syn::Result<_>>()?;
674
675 let field_names: Vec<&syn::Ident> = field_data.iter().map(|(id, _, _)| *id).collect();
676
677 let (body, owned_body, segment_tag_impl) = if let Some(seg_tag) = &struct_attrs.segment {
678 let qualifier_guard = if let Some(qual) = &struct_attrs.qualifier {
680 quote! {
681 if __seg.element_str(0).unwrap_or("") != #qual {
682 return ::core::result::Result::Err(
683 ::edifact_rs::EdifactError::MissingRequiredElement {
684 tag: #seg_tag.to_owned(),
685 element_index: 0,
686 }
687 );
688 }
689 }
690 } else if let Some(idx) = struct_attrs.qualifier_from {
691 quote! {
692 if __seg.element_str(#idx as usize).unwrap_or("").is_empty() {
693 return ::core::result::Result::Err(
694 ::edifact_rs::EdifactError::MissingRequiredElement {
695 tag: #seg_tag.to_owned(),
696 element_index: #idx as usize,
697 }
698 );
699 }
700 }
701 } else {
702 quote! {}
703 };
704
705 let find_seg = if let Some(qual) = &struct_attrs.qualifier {
706 quote! {
707 ::edifact_rs::find_qualified_segment(segments, #seg_tag, #qual)
708 }
709 } else {
710 quote! {
711 ::edifact_rs::find_segment(segments, #seg_tag)
712 }
713 };
714
715 let field_inits: Vec<TokenStream2> = field_data
716 .iter()
717 .enumerate()
718 .map(|(decl_i, (ident, ty, attrs))| -> syn::Result<TokenStream2> {
719 let idx = attrs.element.unwrap_or(decl_i as u32) as usize;
720 if attrs.composite {
721 if is_option_type(ty) {
722 let inner_ty = option_inner_type(ty)
723 .ok_or_else(|| syn::Error::new(ident.span(), "expected Option<T>"))?;
724 return Ok(quote! {
725 let #ident = match ::edifact_rs::composite_element(__seg, #idx) {
726 ::core::option::Option::Some(__composite) => {
727 ::core::option::Option::Some(
728 <#inner_ty as ::edifact_rs::EdifactCompositeDeserialize>::edifact_deserialize_composite(__composite)?
729 )
730 }
731 ::core::option::Option::None => ::core::option::Option::None,
732 };
733 });
734 }
735 return Ok(quote! {
736 let #ident = <#ty as ::edifact_rs::EdifactCompositeDeserialize>::edifact_deserialize_composite(
737 ::edifact_rs::composite_element(__seg, #idx).ok_or_else(|| ::edifact_rs::EdifactError::MissingRequiredElement {
738 tag: #seg_tag.to_owned(),
739 element_index: #idx as usize,
740 })?
741 )?;
742 });
743 }
744 let value_expr = if let Some(comp) = attrs.component {
745 let comp = comp as usize;
746 quote! {
747 __seg.get_element(#idx).and_then(|__e| __e.get_component(#comp))
748 }
749 } else {
750 quote! { __seg.element_str(#idx) }
751 };
752 Ok(if is_option_type(ty) {
753 quote! {
754 let #ident = #value_expr
755 .filter(|__s| !__s.is_empty())
756 .map(::std::string::String::from);
757 }
758 } else {
759 quote! {
760 let #ident = #value_expr
761 .filter(|__s| !__s.is_empty())
762 .ok_or_else(|| ::edifact_rs::EdifactError::MissingRequiredElement {
763 tag: #seg_tag.to_owned(),
764 element_index: #idx as usize,
765 })?
766 .to_owned();
767 }
768 })
769 })
770 .collect::<syn::Result<_>>()?;
771
772 let body = quote! {
773 let __seg = #find_seg
774 .ok_or_else(|| ::edifact_rs::EdifactError::MissingSegment {
775 tag: #seg_tag.to_owned(),
776 expected_position: "message body".to_owned(),
777 })?;
778 #qualifier_guard
779 #(#field_inits)*
780 ::core::result::Result::Ok(Self { #(#field_names),* })
781 };
782
783 let qualifier_match = if let Some(qual) = &struct_attrs.qualifier {
785 quote! {
786 fn matches_segment(seg: &::edifact_rs::Segment<'_>) -> bool {
787 seg.tag == Self::SEGMENT_TAG
788 && seg.element_str(0).unwrap_or("") == #qual
789 }
790 }
791 } else if let Some(idx) = struct_attrs.qualifier_from {
792 quote! {
793 fn matches_segment(seg: &::edifact_rs::Segment<'_>) -> bool {
794 seg.tag == Self::SEGMENT_TAG
795 && !seg.element_str(#idx as usize).unwrap_or("").is_empty()
796 }
797 }
798 } else {
799 quote! {}
800 };
801
802 let seg_tag_impl = quote! {
803 impl ::edifact_rs::EdifactSegmentTag for #name {
804 const SEGMENT_TAG: &'static str = #seg_tag;
805 #qualifier_match
806 }
807 };
808
809 let find_seg_owned = if let Some(qual) = &struct_attrs.qualifier {
812 quote! {
813 ::edifact_rs::find_qualified_segment_owned(segments, #seg_tag, #qual)
814 }
815 } else {
816 quote! {
817 ::edifact_rs::find_segment_owned(segments, #seg_tag)
818 }
819 };
820
821 let field_inits_owned: Vec<TokenStream2> = field_data
822 .iter()
823 .enumerate()
824 .map(|(decl_i, (ident, ty, attrs))| -> syn::Result<TokenStream2> {
825 let idx = attrs.element.unwrap_or(decl_i as u32) as usize;
826 if attrs.composite {
827 if is_option_type(ty) {
828 let inner_ty = option_inner_type(ty)
829 .ok_or_else(|| syn::Error::new(ident.span(), "expected Option<T>"))?;
830 return Ok(quote! {
831 let #ident = match __seg.elements.get(#idx) {
832 ::core::option::Option::Some(__e) => {
833 let __cows = __e.components.iter()
834 .map(|s| ::std::borrow::Cow::Borrowed(s.as_str()))
835 .collect::<::std::vec::Vec<::std::borrow::Cow<'_, str>>>();
836 ::core::option::Option::Some(
837 <#inner_ty as ::edifact_rs::EdifactCompositeDeserialize>::edifact_deserialize_composite(
838 ::edifact_rs::CompositeElement::from_slice(&__cows)
839 )?
840 )
841 }
842 ::core::option::Option::None => ::core::option::Option::None,
843 };
844 });
845 }
846 return Ok(quote! {
847 let #ident = {
848 let __cows = __seg.elements.get(#idx)
849 .ok_or_else(|| ::edifact_rs::EdifactError::MissingRequiredElement {
850 tag: #seg_tag.to_owned(),
851 element_index: #idx as usize,
852 })?
853 .components.iter()
854 .map(|s| ::std::borrow::Cow::Borrowed(s.as_str()))
855 .collect::<::std::vec::Vec<::std::borrow::Cow<'_, str>>>();
856 <#ty as ::edifact_rs::EdifactCompositeDeserialize>::edifact_deserialize_composite(
857 ::edifact_rs::CompositeElement::from_slice(&__cows)
858 )?
859 };
860 });
861 }
862 let value_expr_owned = if let Some(comp) = attrs.component {
863 let comp = comp as usize;
864 quote! { __seg.component_str(#idx, #comp) }
865 } else {
866 quote! { __seg.element_str(#idx) }
867 };
868 Ok(if is_option_type(ty) {
869 quote! {
870 let #ident = #value_expr_owned
871 .filter(|__s| !__s.is_empty())
872 .map(::std::string::String::from);
873 }
874 } else {
875 quote! {
876 let #ident = #value_expr_owned
877 .filter(|__s| !__s.is_empty())
878 .ok_or_else(|| ::edifact_rs::EdifactError::MissingRequiredElement {
879 tag: #seg_tag.to_owned(),
880 element_index: #idx as usize,
881 })?
882 .to_owned();
883 }
884 })
885 })
886 .collect::<syn::Result<_>>()?;
887
888 let owned_body = quote! {
889 let __seg = #find_seg_owned
890 .ok_or_else(|| ::edifact_rs::EdifactError::MissingSegment {
891 tag: #seg_tag.to_owned(),
892 expected_position: "message body".to_owned(),
893 })?;
894 #qualifier_guard
895 #(#field_inits_owned)*
896 ::core::result::Result::Ok(Self { #(#field_names),* })
897 };
898
899 (body, owned_body, seg_tag_impl)
900 } else {
901 let field_inits: Vec<TokenStream2> = field_data
903 .iter()
904 .map(|(ident, ty, attrs)| -> syn::Result<TokenStream2> {
905 Ok(if let Some(qual) = &attrs.qualifier {
906 if attrs.group || is_vec_type(ty) {
907 let inner_ty = vec_inner_type(ty)
908 .ok_or_else(|| syn::Error::new(ident.span(), "expected Vec<T>"))?;
909 quote! {
910 let #ident = segments
911 .iter()
912 .filter(|__seg| {
913 __seg.tag == <#inner_ty as ::edifact_rs::EdifactSegmentTag>::SEGMENT_TAG
914 && __seg.element_str(0).unwrap_or("") == #qual
915 })
916 .map(|__seg| {
917 ::edifact_rs::EdifactDeserialize::edifact_deserialize(
918 ::core::slice::from_ref(__seg),
919 )
920 })
921 .collect::<::core::result::Result<::std::vec::Vec<#inner_ty>, ::edifact_rs::EdifactError>>()?;
922 }
923 } else if is_option_type(ty) {
924 let inner_ty = option_inner_type(ty)
925 .ok_or_else(|| syn::Error::new(ident.span(), "expected Option<T>"))?;
926 quote! {
927 let #ident = match ::edifact_rs::find_qualified_segment(
928 segments,
929 <#inner_ty as ::edifact_rs::EdifactSegmentTag>::SEGMENT_TAG,
930 #qual,
931 ) {
932 ::core::option::Option::Some(__seg) => {
933 ::core::option::Option::Some(
934 ::edifact_rs::EdifactDeserialize::edifact_deserialize(
935 ::core::slice::from_ref(__seg),
936 )?
937 )
938 }
939 ::core::option::Option::None => ::core::option::Option::None,
940 };
941 }
942 } else {
943 quote! {
944 let __seg = ::edifact_rs::find_qualified_segment(
945 segments,
946 <#ty as ::edifact_rs::EdifactSegmentTag>::SEGMENT_TAG,
947 #qual,
948 )
949 .ok_or_else(|| ::edifact_rs::EdifactError::MissingSegment {
950 tag: <#ty as ::edifact_rs::EdifactSegmentTag>::SEGMENT_TAG.to_owned(),
951 expected_position: "message body".to_owned(),
952 })?;
953 let #ident = ::edifact_rs::EdifactDeserialize::edifact_deserialize(
954 ::core::slice::from_ref(__seg),
955 )?;
956 }
957 }
958 } else if attrs.group || is_vec_type(ty) {
959 let inner_ty = vec_inner_type(ty)
960 .ok_or_else(|| syn::Error::new(ident.span(), "expected Vec<T>"))?;
961 quote! {
962 let #ident = ::edifact_rs::find_segments_typed::<#inner_ty>(segments)
963 .map(|__seg| {
964 <#inner_ty as ::edifact_rs::EdifactDeserialize>::edifact_deserialize(
965 ::core::slice::from_ref(__seg),
966 )
967 })
968 .collect::<::core::result::Result<::std::vec::Vec<#inner_ty>, _>>()?;
969 }
970 } else if is_option_type(ty) {
971 let inner_ty = option_inner_type(ty)
972 .ok_or_else(|| syn::Error::new(ident.span(), "expected Option<T>"))?;
973 quote! {
974 let #ident = if segments
975 .iter()
976 .any(|__seg| __seg.tag == <#inner_ty as ::edifact_rs::EdifactSegmentTag>::SEGMENT_TAG)
977 {
978 ::core::option::Option::Some(
979 <#inner_ty as ::edifact_rs::EdifactDeserialize>::edifact_deserialize(segments)?
980 )
981 } else {
982 ::core::option::Option::None
983 };
984 }
985 } else {
986 quote! {
987 let #ident = ::edifact_rs::EdifactDeserialize::edifact_deserialize(segments)?;
988 }
989 })
990 })
991 .collect::<syn::Result<_>>()?;
992
993 let body = quote! {
994 #(#field_inits)*
995 ::core::result::Result::Ok(Self { #(#field_names),* })
996 };
997
998 let field_inits_owned: Vec<TokenStream2> = field_data
1001 .iter()
1002 .map(|(ident, ty, attrs)| -> syn::Result<TokenStream2> {
1003 Ok(if let Some(qual) = &attrs.qualifier {
1004 if attrs.group || is_vec_type(ty) {
1005 let inner_ty = vec_inner_type(ty)
1006 .ok_or_else(|| syn::Error::new(ident.span(), "expected Vec<T>"))?;
1007 quote! {
1008 let #ident = segments
1009 .iter()
1010 .filter(|__seg| {
1011 __seg.tag == <#inner_ty as ::edifact_rs::EdifactSegmentTag>::SEGMENT_TAG
1012 && __seg.element_str(0).unwrap_or("") == #qual
1013 })
1014 .map(|__seg| {
1015 <#inner_ty as ::edifact_rs::EdifactDeserialize>::edifact_deserialize_owned(
1016 ::core::slice::from_ref(__seg),
1017 )
1018 })
1019 .collect::<::core::result::Result<::std::vec::Vec<#inner_ty>, ::edifact_rs::EdifactError>>()?;
1020 }
1021 } else if is_option_type(ty) {
1022 let inner_ty = option_inner_type(ty)
1023 .ok_or_else(|| syn::Error::new(ident.span(), "expected Option<T>"))?;
1024 quote! {
1025 let #ident = match ::edifact_rs::find_qualified_segment_owned(
1026 segments,
1027 <#inner_ty as ::edifact_rs::EdifactSegmentTag>::SEGMENT_TAG,
1028 #qual,
1029 ) {
1030 ::core::option::Option::Some(__seg) => {
1031 ::core::option::Option::Some(
1032 <#inner_ty as ::edifact_rs::EdifactDeserialize>::edifact_deserialize_owned(
1033 ::core::slice::from_ref(__seg),
1034 )?
1035 )
1036 }
1037 ::core::option::Option::None => ::core::option::Option::None,
1038 };
1039 }
1040 } else {
1041 quote! {
1042 let __seg = ::edifact_rs::find_qualified_segment_owned(
1043 segments,
1044 <#ty as ::edifact_rs::EdifactSegmentTag>::SEGMENT_TAG,
1045 #qual,
1046 )
1047 .ok_or_else(|| ::edifact_rs::EdifactError::MissingSegment {
1048 tag: <#ty as ::edifact_rs::EdifactSegmentTag>::SEGMENT_TAG.to_owned(),
1049 expected_position: "message body".to_owned(),
1050 })?;
1051 let #ident = <#ty as ::edifact_rs::EdifactDeserialize>::edifact_deserialize_owned(
1052 ::core::slice::from_ref(__seg),
1053 )?;
1054 }
1055 }
1056 } else if attrs.group || is_vec_type(ty) {
1057 let inner_ty = vec_inner_type(ty)
1058 .ok_or_else(|| syn::Error::new(ident.span(), "expected Vec<T>"))?;
1059 quote! {
1060 let #ident = segments
1061 .iter()
1062 .filter(|__seg| <#inner_ty as ::edifact_rs::EdifactSegmentTag>::matches_owned_segment(__seg))
1063 .map(|__seg| {
1064 <#inner_ty as ::edifact_rs::EdifactDeserialize>::edifact_deserialize_owned(
1065 ::core::slice::from_ref(__seg),
1066 )
1067 })
1068 .collect::<::core::result::Result<::std::vec::Vec<#inner_ty>, _>>()?;
1069 }
1070 } else if is_option_type(ty) {
1071 let inner_ty = option_inner_type(ty)
1072 .ok_or_else(|| syn::Error::new(ident.span(), "expected Option<T>"))?;
1073 quote! {
1074 let #ident = if segments
1075 .iter()
1076 .any(|__seg| __seg.tag == <#inner_ty as ::edifact_rs::EdifactSegmentTag>::SEGMENT_TAG)
1077 {
1078 ::core::option::Option::Some(
1079 <#inner_ty as ::edifact_rs::EdifactDeserialize>::edifact_deserialize_owned(segments)?
1080 )
1081 } else {
1082 ::core::option::Option::None
1083 };
1084 }
1085 } else {
1086 quote! {
1087 let #ident = <#ty as ::edifact_rs::EdifactDeserialize>::edifact_deserialize_owned(segments)?;
1088 }
1089 })
1090 })
1091 .collect::<syn::Result<_>>()?;
1092
1093 let owned_body = quote! {
1094 #(#field_inits_owned)*
1095 ::core::result::Result::Ok(Self { #(#field_names),* })
1096 };
1097
1098 (body, owned_body, quote! {})
1099 };
1100
1101 Ok(quote! {
1102 impl ::edifact_rs::EdifactDeserialize for #name {
1103 fn edifact_deserialize(
1104 segments: &[::edifact_rs::Segment<'_>],
1105 ) -> ::core::result::Result<Self, ::edifact_rs::EdifactError> {
1106 #body
1107 }
1108
1109 fn edifact_deserialize_owned(
1110 segments: &[::edifact_rs::OwnedSegment],
1111 ) -> ::core::result::Result<Self, ::edifact_rs::EdifactError> {
1112 #owned_body
1113 }
1114 }
1115 #segment_tag_impl
1116 })
1117}
1118
1119#[cfg(test)]
1120mod tests {
1121 #[test]
1122 fn trybuild_ui() {
1123 let t = trybuild::TestCases::new();
1124 t.pass("tests/ui/pass_*.rs");
1125 t.compile_fail("tests/ui/fail_*.rs");
1126 }
1127}