linked_data_core/
rdf_metadata.rs1use std::marker::PhantomData;
2
3use oxiri::Iri;
4use proc_macro_error::abort;
5use syn::DeriveInput;
6use syn::spanned::Spanned;
7use syn::visit::Visit;
8
9use crate::attributes::field::RdfFieldAttributes;
10use crate::attributes::r#type::{RdfEnumAttributes, RdfStructAttributes};
11use crate::attributes::variant::{PredicatePath, RdfVariantAttributes};
12use crate::prefix_mappings::PrefixMappings;
13use crate::{Error, TokenGenerator};
14
15pub enum RdfType<F> {
16 Enum(RdfEnum<F>),
17 Struct(RdfStruct<F>),
18}
19
20pub struct RdfEnum<G> {
21 attributes: RdfEnumAttributes,
22 pub ident: syn::Ident,
23 pub variants: Vec<RdfVariant<G>>,
24}
25
26pub struct RdfVariant<G> {
27 attributes: RdfVariantAttributes,
28 pub index: usize,
29 pub ty: syn::Type,
30 _generator: PhantomData<G>,
31}
32
33pub struct RdfStruct<G> {
34 attributes: RdfStructAttributes,
35 pub ident: syn::Ident,
36 pub fields: Vec<RdfField<G>>,
37}
38
39#[derive(Debug)]
40pub struct RdfField<G> {
41 attributes: RdfFieldAttributes,
42 pub ty: syn::Type,
43 _generator: PhantomData<G>,
44}
45
46pub fn unwrap_or_abort<T>(result: Result<T, Error>) -> T {
47 match result {
48 Ok(value) => value,
49 Err(error) => abort!(error.span(), error),
50 }
51}
52
53impl<G: TokenGenerator> RdfType<G> {
54 pub fn from_derive(derive_input: DeriveInput) -> Self {
55 unwrap_or_abort(Self::try_from_derive(derive_input))
56 }
57
58 fn try_from_derive(derive_input: DeriveInput) -> Result<Self, Error> {
59 match derive_input.data {
60 syn::Data::Struct(data) => {
61 let mut r#struct = RdfStruct {
62 ident: derive_input.ident,
63 attributes: derive_input.attrs.try_into()?,
64 fields: vec![],
65 };
66 r#struct.visit_data_struct(&data);
67 Ok(RdfType::Struct(r#struct))
68 }
69 syn::Data::Enum(data) => {
70 let mut r#enum = RdfEnum {
71 ident: derive_input.ident,
72 attributes: derive_input.attrs.try_into()?,
73 variants: vec![],
74 };
75 r#enum.visit_data_enum(&data);
76 Ok(RdfType::Enum(r#enum))
77 }
78 syn::Data::Union(data_union) => Err(Error::UnionType {
79 span: data_union.union_token.span(),
80 }),
81 }
82 }
83}
84
85impl<'ast, F> Visit<'ast> for RdfEnum<F> {
86 fn visit_variant(&mut self, variant: &'ast syn::Variant) {
87 let variant = unwrap_or_abort(RdfVariant::from_variant(
88 variant.clone(),
89 self.variants.len(),
90 &self.attributes.prefix_mappings,
91 ));
92 self.variants.push(variant);
93 }
94}
95
96impl<F> RdfVariant<F> {
97 fn from_variant(
98 variant: syn::Variant,
99 index: usize,
100 prefix_mappings: &PrefixMappings,
101 ) -> Result<Self, Error> {
102 let mut fields = variant.fields.iter();
103
104 let Some(field) = fields.next() else {
105 return Err(Error::UnitVariant {
106 span: variant.span(),
107 });
108 };
109
110 if let Some(field) = fields.next() {
111 return Err(Error::StructVariant { span: field.span() });
112 }
113
114 Ok(RdfVariant {
115 attributes: RdfVariantAttributes::try_from_attrs(
116 &variant,
117 field.attrs.clone(),
118 variant.attrs.clone(),
119 prefix_mappings,
120 )?,
121 index,
122 ty: field.ty.clone(),
123 _generator: PhantomData,
124 })
125 }
126
127 pub fn predicate_path(&self) -> &PredicatePath {
128 &self.attributes.predicate_path
129 }
130}
131
132impl<G> RdfStruct<G> {
133 pub fn type_iri(&self) -> Option<&Iri<String>> {
134 self.attributes.r#type.as_ref()
135 }
136
137 pub fn prefix_mappings(&self) -> &PrefixMappings {
138 &self.attributes.prefix_mappings
139 }
140}
141
142impl<'ast, F> Visit<'ast> for RdfStruct<F> {
143 fn visit_field(&mut self, field: &'ast syn::Field) {
144 let rdf_field = unwrap_or_abort(RdfField::try_from_field(
145 field.clone(),
146 &self.attributes.prefix_mappings,
147 ));
148 self.fields.push(rdf_field);
149 }
150}
151
152impl<F> RdfField<F> {
153 fn try_from_field(field: syn::Field, prefix_mappings: &PrefixMappings) -> Result<Self, Error> {
154 let attributes = RdfFieldAttributes::try_from_attrs(field.attrs, prefix_mappings)?;
155
156 Ok(RdfField {
157 attributes,
158 ty: field.ty,
159 _generator: PhantomData,
160 })
161 }
162
163 pub fn is_flattened(&self) -> bool {
164 self.attributes.flatten
165 }
166
167 pub fn is_graph(&self) -> bool {
168 self.attributes.is_graph
169 }
170
171 pub fn is_ignored(&self) -> bool {
172 self.attributes.ignore
173 }
174
175 pub fn predicate(&self) -> Option<&Iri<String>> {
176 self.attributes.predicate.as_ref()
177 }
178
179 pub fn is_id(&self) -> bool {
180 self.attributes.is_id
181 }
182}