Enums and reusable type constraints


#1

I’m building an implementation in Rust of an underlying serializable data model. The underlying model has atomic primitives and union types (among others).

I.e., imagine a set of name/value pairs, where, like JSON, the value can be an atom, an object, or a list of atoms or object or a union of atoms or objects.

Just atomic primitives would be pretty easy: build a enum of the underlying primitives (similar to what rustc_serializable or serde does with JSON primitives).

Dealing with arbitrary union types is a bit more tricky because I can’t easily constrain the union to subsets of the primitives (refinement types?).

I can model the primitives, create an Atom or Value enum, and then create an enum for each union type, but that’s a lot of indirection.

Is there a cleaner way of using Rust’s type system that’s obvious? I’ve thought, e.g., about a marker trait and using a generic type constrained only to marked items, but everything ends up looking super complex…


#2

Using variants to represent expressions is fine. This sort of thing is well done using such variants to represent a statement, expression, values and so on.

Here (I don’t know if this will help) an example of a simple system of expressions:

enum Expr {
    Add(Box<Expr>, Box<Expr>),
    Sub(Box<Expr>, Box<Expr>),
    Num(i32),
}

impl Expr {
    fn eval(&self) -> i32 {
        match *self {
            Expr::Add(ref a, ref b) =>
                eval(a) + eval(b),
            Expr::Sub(ref a, ref b) =>
                eval(a) - eval(b),
            Expr::Num(x) =>
                x,
        }
    }
}

edit: But, in most of cases, there’s lots of crates that does this job as well. Like parsers, lexers and so on. I’d recommend you to look for one.