linked_data_core/attributes/
variant.rs

1use iref::IriBuf;
2use snafu::ResultExt;
3use syn::spanned::Spanned;
4
5use crate::attributes::ast::VariantAttribute;
6use crate::attributes::parse_ld_attributes;
7use crate::prefix_mappings::PrefixMappings;
8use crate::{Error, InvalidMappingSnafu};
9
10pub struct RdfVariantAttributes {
11  pub predicate_path: PredicatePath,
12}
13
14pub enum PredicatePath {
15  // Represents a path with an intermediate blank node
16  // :s <to_blank> _:blank .
17  // _:blank <from_blank> :o .
18  ChainedPath {
19    to_blank: IriBuf,
20    from_blank: IriBuf,
21  },
22
23  // For the direct case:
24  // :s :predicate :o .
25  Predicate(IriBuf),
26}
27
28impl RdfVariantAttributes {
29  pub fn try_from_attrs(
30    variant: &syn::Variant,
31    inner_attrs: Vec<syn::Attribute>,
32    outer_attrs: Vec<syn::Attribute>,
33    prefix_mappings: &PrefixMappings,
34  ) -> Result<Self, Error> {
35    let inner_attrs: Vec<VariantAttribute> = parse_ld_attributes(&inner_attrs)?;
36    let outer_attrs: Vec<VariantAttribute> = parse_ld_attributes(&outer_attrs)?;
37
38    let unpack_variant_attrs = |attrs: &[VariantAttribute]| -> Result<Option<IriBuf>, Error> {
39      if let Some(VariantAttribute::Iri(iri)) = attrs.get(1) {
40        Err(Error::MultipleIris { span: iri.span() })
41      } else {
42        attrs
43          .first()
44          .map(|variant_attr| match variant_attr {
45            VariantAttribute::Iri(lit_str) => lit_str,
46          })
47          .map(|lit_str| {
48            prefix_mappings
49              .expand(lit_str.value())
50              .context(InvalidMappingSnafu {
51                span: lit_str.span(),
52              })
53          })
54          .transpose()
55      }
56    };
57
58    let inner_attr = unpack_variant_attrs(&inner_attrs)?;
59    let outer_attr = unpack_variant_attrs(&outer_attrs)?;
60
61    match (inner_attr, outer_attr) {
62      (None, None) => Err(Error::MissingIriAttribute {
63        span: variant.span(),
64      }),
65      (None, Some(outer_iri)) => Ok(RdfVariantAttributes {
66        predicate_path: PredicatePath::Predicate(outer_iri),
67      }),
68      (Some(inner_iri), None) => Ok(RdfVariantAttributes {
69        predicate_path: PredicatePath::Predicate(inner_iri),
70      }),
71      (Some(to_blank), Some(from_blank)) => Ok(RdfVariantAttributes {
72        predicate_path: PredicatePath::ChainedPath {
73          to_blank,
74          from_blank,
75        },
76      }),
77    }
78  }
79}