The problem is there are two cases to turn RDF into a Rust type:
The type is simple like i32 or String that can be built from a single RDF-term.
The type is complex like A where the graph has to be traversed to get all information that is needed.
In the end, I have to check if a field's type implements FromGraph or FromTerm to call the right fucntion.However, as far as I understand this is not possible because macro expansion is done before any type information is gathered.
Luckily RDF itself destinguishes between object- and data-predicates which are exactly what I need. But I don't know how to put it into my derive's syntax.
Should I use explicit syntax like:
#[crdf(object_predicate = ...)] // and
#[crdf(data_predicate = ...)]
I'm reluctent to do that because this would be handled by the user which is always a good source of errors.
Or can I add some other metadata to the predicates passed into the attribute, e.g. I could imagine a HashMap where the terms mapped are either object- or data-predicates.
I don't think you need to generate two sets of code here, I'm not familiar with RDF, but aren't those just two implementations of some FromRDF trait which tries to build a T given a reference to the graph and a particular term?
Sure, you'd need to write some boring impls for the primitive types and less-boring ones for custom containers, but once the building blocks exist you'll be able to use your custom derive to build up more interesting things.
Yes of course you are right the FromGraph-side can be simplyfied.
I guess I picked the wrong example. The real problem occures when building a graph that represents a Rust type. In RDF knwoledge is represented as subject-predicate-object triples (RDF-triples).
Now to stich with the example of A and B a graph for A would for example be:
Three RDF-triples, two with the subject URI of a, one with the root subject of b.
For this case I use the Iterator presented in this Topic.
I.e. an implementation for GetTriplesIter for A would look like:
impl GetTriplesIter for A {
fn triples_iter<'a, TD>(&'a self, s: Term<TD>) -> TriplesIter<'a, TD>
where
TD: TermData,
{
let mut creators = VecDeque::new();
let c = Box::new(move |s: Term<TD>| {
[s, rdf::value.clone(), self.value.to_term()]
}) as _;
creators.push(c);
let b_uri = create_uri_for_b();
let b_uri1 = b_uri.clone();
let c = Box::new(move |s: Term<TD>| {
[s, HAS_B.clone(), b_uri1]
}) as _;
creators.push(c);
let mut children = VecDeque::new();
let child = self.b.triples_iter(b_uri);
children.push(child)
TriplesIter::new_with_children(s, creators, children)
}
}
And now you can no longer build a simplyfied trait covering everything because in one case a boxed closure has to be build and in the other case a boxed closure and an iterator.