linked_data_core/
rdf_metadata.rs1use std::marker::PhantomData;
2
3use oxiri::Iri;
4use proc_macro_error3::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: Option<syn::Type>,
35 _generator: PhantomData<G>,
36}
37
38pub struct RdfStruct<G> {
39 attributes: RdfStructAttributes,
40 pub ident: syn::Ident,
41 pub fields: Vec<RdfField<G>>,
42}
43
44#[derive(Debug)]
45pub struct RdfField<G> {
46 attributes: RdfFieldAttributes,
47 pub ty: syn::Type,
48 _generator: PhantomData<G>,
49}
50
51pub fn unwrap_or_abort<T>(result: Result<T, Error>) -> T {
52 match result {
53 Ok(value) => value,
54 Err(error) => abort!(error.span(), error),
55 }
56}
57
58impl<G: TokenGenerator> RdfType<G> {
59 pub fn from_derive(derive_input: DeriveInput) -> Self {
60 unwrap_or_abort(Self::try_from_derive(derive_input))
61 }
62
63 fn try_from_derive(derive_input: DeriveInput) -> Result<Self, Error> {
64 match derive_input.data {
65 syn::Data::Struct(data) => {
66 let mut r#struct = RdfStruct {
67 ident: derive_input.ident,
68 attributes: derive_input.attrs.try_into()?,
69 fields: vec![],
70 };
71 r#struct.visit_data_struct(&data);
72 Ok(RdfType::Struct(r#struct))
73 }
74 syn::Data::Enum(data) => {
75 let mut r#enum = RdfEnum {
76 ident: derive_input.ident,
77 attributes: derive_input.attrs.try_into()?,
78 variants: vec![],
79 };
80 r#enum.visit_data_enum(&data);
81
82 let has_unit_variant = r#enum.variants.iter().any(|variant| variant.ty.is_none());
83 let has_data_variant = r#enum.variants.iter().any(|variant| variant.ty.is_some());
84 if has_unit_variant && has_data_variant {
85 return Err(Error::MixedVariantKinds {
86 span: data.enum_token.span(),
87 });
88 }
89
90 Ok(RdfType::Enum(r#enum))
91 }
92 syn::Data::Union(data_union) => Err(Error::UnionType {
93 span: data_union.union_token.span(),
94 }),
95 }
96 }
97}
98
99impl<G> RdfEnum<G> {
100 pub fn is_closed_list(&self) -> bool {
105 self.variants.first().is_none_or(RdfVariant::is_unit)
106 }
107
108 pub fn prefix_mappings(&self) -> &PrefixMappings {
109 &self.attributes.prefix_mappings
110 }
111}
112
113impl<'ast, F> Visit<'ast> for RdfEnum<F> {
114 fn visit_variant(&mut self, variant: &'ast syn::Variant) {
115 let variant = unwrap_or_abort(RdfVariant::from_variant(
116 variant.clone(),
117 self.variants.len(),
118 &self.attributes.prefix_mappings,
119 ));
120 self.variants.push(variant);
121 }
122}
123
124impl<F> RdfVariant<F> {
125 fn from_variant(
126 variant: syn::Variant,
127 index: usize,
128 prefix_mappings: &PrefixMappings,
129 ) -> Result<Self, Error> {
130 let mut fields = variant.fields.iter();
131 let field = fields.next();
132
133 if let Some(extra_field) = fields.next() {
134 return Err(Error::StructVariant {
135 span: extra_field.span(),
136 });
137 }
138
139 let (inner_attrs, ty) = match field {
140 Some(field) => (field.attrs.clone(), Some(field.ty.clone())),
141 None => (vec![], None),
142 };
143
144 Ok(RdfVariant {
145 attributes: RdfVariantAttributes::try_from_attrs(
146 &variant,
147 inner_attrs,
148 variant.attrs.clone(),
149 prefix_mappings,
150 )?,
151 index,
152 ty,
153 _generator: PhantomData,
154 })
155 }
156
157 pub fn predicate_path(&self) -> &PredicatePath {
158 &self.attributes.predicate_path
159 }
160
161 pub fn is_unit(&self) -> bool {
164 self.ty.is_none()
165 }
166}
167
168impl<G> RdfStruct<G> {
169 pub fn type_iri(&self) -> Option<&Iri<String>> {
170 self.attributes.r#type.as_ref()
171 }
172
173 pub fn prefix_mappings(&self) -> &PrefixMappings {
174 &self.attributes.prefix_mappings
175 }
176}
177
178impl<'ast, F> Visit<'ast> for RdfStruct<F> {
179 fn visit_field(&mut self, field: &'ast syn::Field) {
180 let rdf_field = unwrap_or_abort(RdfField::try_from_field(
181 field.clone(),
182 &self.attributes.prefix_mappings,
183 ));
184 self.fields.push(rdf_field);
185 }
186}
187
188impl<F> RdfField<F> {
189 fn try_from_field(field: syn::Field, prefix_mappings: &PrefixMappings) -> Result<Self, Error> {
190 let attributes = RdfFieldAttributes::try_from_attrs(field.attrs, prefix_mappings)?;
191
192 Ok(RdfField {
193 attributes,
194 ty: field.ty,
195 _generator: PhantomData,
196 })
197 }
198
199 pub fn is_flattened(&self) -> bool {
200 self.attributes.flatten
201 }
202
203 pub fn is_graph(&self) -> bool {
204 self.attributes.is_graph
205 }
206
207 pub fn is_ignored(&self) -> bool {
208 self.attributes.ignore
209 }
210
211 pub fn predicate(&self) -> Option<&Iri<String>> {
212 self.attributes.predicate.as_ref()
213 }
214
215 pub fn is_id(&self) -> bool {
216 self.attributes.is_id
217 }
218}