Avoid heavily wiring-in enum for building this graph?

I'm deserializing a Lake of "units" to form a tree of Apexes and then "hydrating" the tree so an apex may have more than one root in full graph form. The unit type is erased so every apex is the same type. Currently, I have a Tray enum behind the Apex that allows it to attempt to produce a String, i32, u64, or other when requested.

Example unit with current setup:

/// For producing a new leaf string apex from list of string apexes
pub struct List {
    items: Vec<Apex>,
    separator: Apex,
}
/// Adapt allows the graph to do things about the child apexes
impl Adapt for List {
    fn adapt(&mut self, deal: &mut dyn Deal) -> Result<()> {
        self.items.deal("items", deal)?;
        self.separator.deal("separator", deal)?;
        Ok(())
    }
}

I want to change Apex to have one generic that is the output type (Tray enum goes away). Notice that the unit is still erased but the output is part of the type now. List unit also goes inside an Apex<String>.

/// Ideal setup
pub struct List {
    items: Vec<Apex<String>>,
    separator: Apex<String>,
}

However, I cannot figure out how to build the graph without some kind of enum that is heavily wired-in. If there must be an enum for the different output types, I want the user to be able to make a custom "output type atlas" in one place that would allow construction of the graph. This image shows the graph stages with ideal Apex<T> that I do not currently have:

Notice the Deal trait in the following code:
Lake: Building tree from lake · GitHub
Graph: Filling graph edges from tree · GitHub
Unit atlas that could inspire an ApexAtlas (with output type included) or be modified to include output type: Custom atlas that allows graph user to load with desired "unit" extensions · GitHub
In the above code links, you can see how I take an Apex that might just be a hash-value (lake) or namespace path (space/scope) and replace with a real Apex (smart pointer).

The Space struct would have to have an enum of Apex<T> instead of Apex and the Deal trait would need to accept an enum of Apex<T> so that it can lineup types to make connections? I would need to do Box<dyn ApexAtlas> similar to Box<dyn DeserializeUnit>
In summary, I think I need to remove built-in limited Tray (enum inside of Apex) and use an outside enum of Apex<T>?

/// user-written enum for working with my graph crate:
enum MyAtlas {
   String(Apex<String>),
   i32(Apex<i32>),
}
impl ApexAtlas for MyAtlas {
 // some magic
}

But then each super crate for custom nodes would have its own ApexAtlas and I cannot figure out how to join/reconcile that.

Please feel free to roast my entire question and tell me what I really need to be asking. I've been struggling with this for a while and my thought process might be limited.

I'll do it then.

It's really hard to follow your line of thought, to not say impossible. Your post is full of incomplete descriptions: Everytime you start describing one part of your current solution, you interrupt it mentioning another part... whose description is also given incomplete.

If you want to receive help, you really need to provide all the information necessary to understand your problem. It's often the case that people find the answer while describing it precisely because they had not thought about it holistically.

2 Likes

Good point. I tried to keep it too short. I'll work on narrowing it down to what I think the crux of the problem is and provide more context.