Pattern for Structure Adapted from OO Language?

#1

Hi,

I have a piece of code that’s written in JavaScript, which I want to port over to Rust. One part that I have a problem with is wrapping my head around how this should be adapted to Rust in an idiomatic way.

This specific part is this: I have a list of 16 types (structs in Rust) that can appear at the same place. These structs are quite large and have specific trait implementations. Every one of them has an id field that contains a unique identifier (uuid).

It looks similar to this:

#[derive(Deserialize)]
pub struct A {
    id: String,
    // …
}

#[derive(Deserialize)]
pub struct B {
    id: String,
    // …
}

At some points, I get a JSON string that might contain any of these structs (with the type given by a property in this JSON). What I do is thus this:

#[derive(Deserialize)]
#[serde(tag="type", content="data", rename_all="lowercase")]
pub enum Entry {
    A(A),
    B(B),
}

This works quite well so far. However, now I want to add relationships given by the unique id:

#[derive(Deserialize)]
#[serde(tag = "type", content = "id", rename_all="lowercase")]
pub enum Relationship {
    A(String),
    B(String),
}

pub enum EntryRef<'a> {
    A(&'a A),
    B(&'a B),
}

impl Relationship {
    pub fn lookup<'a>(&self, objects: &'a HashSet<Entry>) -> Option<EntryRef<'a>> {
        // look for entry with given type and id in objects
    }
}

Now I have basically the same enum three times in there, in addition to the original structs. This means that whenever I add a new type, I have to add it to four places in my code.

Is there a way to unify this so I only need a single place to add new types? I thought about using a single enum instead of all those structs, but that would mean that the vast majority of my code would have to be in the same file (since you can’t add variants to enums defined in other modules), and it also wouldn’t fix the relationship issue.

#2

It looks all right. You’re going to need the two enums for Serde either way.

For lookup, maybe you could use Any? But it does have its own boilerplate.

Another option is code generation. You could generate all enums at once using a custom macro.