Looking to write a set of traits make any data structure look like an XML DOM tree. This would allow easy read, write, and query. I've come up with these traits and wonder if they are idiomatic.
I've not managed to specialize Node for every Element, every Attribute and every Text, since those implementations conflict with each other: the compiler does not know that an Element is never a Text. So each implementation of Element would also need to implement Node.
Perhaps there's a already a crate with similar traits.
@vitalyd Yes, a concrete implementation might use enums. These traits could be implemented by those enums. The idea is to have traits so that DOM related algorithms can be reused for different data models.
I think one would generally model the entire DOM as a single enum. That would make implementing your traits messy, if not impossible (at least as they're specified here) because not every variant of this enum fits the trait. Splitting the DOM into multiple enums seems gnarly and likely to lead to spaghetti code. But maybe I didn't think this through hard enough.
What types of (DOM-like) data models are you thinking of abstracting over?
As for the existing traits, you might be able to use specialization to provide default method impls but then specialize them for concrete types.
The goal is to have a DOM for rich XML documents. I'd like to derive the code from Relax NG. That can lead to hundreds of classes and attributes. The code would make access to the data model for the XML model typesafe. This is to enforce nesting and cardinality rules.
Traits are fundamentally open-world entities: setting up multiple blanket implementations is generally problematic. I think there are ways to use macros to make implementations less tedious without running into this issue.
In any case, I don't think this function achieves what you (likely) intended:
fn as_attribute(&self) -> Option<&Self>
where
Self: Attribute<'a>,
{
None
}
The where clause does not provide evidence that Self: Attribute<'a>. Rather, it demands evidence upfront (whether it returns Some or None has no bearing on this). Therefore, you can't really use it to test whether it is an attribute or not at run time – if it isn't the compilation would simply fail.
What you probably want instead is something along the lines of MOPA: My Own Personal Any. That gives you the ability to conditionally downcast trait objects at run time.
error[E0277]: the trait bound `Self: std::marker::Sized` is not satisfied
|
93 | element: self,
| ^^^^ `Self` does not have a constant size known at compile-time
|
= help: the trait `std::marker::Sized` is not implemented for `Self`
= help: consider adding a `where Self: std::marker::Sized` bound
= note: required for the cast to the object type `trai::Element<'_>`
error: aborting due to previous error
I do not know why it is giving this error, because the member element of ElementChildIterator is a reference and should simply have the size of a pointer.