Assign associated non mutable constant data to enum variants

329 Views Asked by At

Note: My question is similar to this question, but doesn't seem to solve my use case. Can enum variants have constant associated values?

Problem explanation

My server returns a country (very long list) which internally is mapped to an enum (there is a closed set of valid possibilities known ahead of time).

I need to have some data associated to the country (for instance the language).

The associated data is "constant" and for ergonomic/performance reasons it makes sense for the data to be "attached" to the enum variation.

Contrived example:

I have a list of languages and a list of countries

#[derive(Serialize,Deserialize)
enum Language {
  English,
  Spanish,
  French,
// .. 100 more
}

#[derive(Serialize,Deserialize)
enum Country {
  USA,
  England,
  France,
  Mexico,
  Spain
// .. 100 more
}

Internally I would like the enum to associate the language value to the country implicitly:

// what I want

#[derive(Serialize,Deserialize)
enum Country {
  USA(Language),
  England(Language),
  // ... more countries with associated languages...
}

  1. When creating a "Country", I don't want to supply the language, rather just Country::country_name (without the language)
  2. when serializing/deserializing, the language should be implicitly added

Looking at serde.rs documentation you could add a field attribute

#[serde(default)]

or

#[serde(default = "path")]

but

  1. default there isn't a default language for all countries - rather it depends on the country variant it is contained in
  2. path - the function is called without the country value, so similar effect to default

Some options I considered

  1. implement serialize/deserialize by hand - but i have many cases and error prone
  2. lazy constant values ? verbose
1

There are 1 best solutions below

0
On

Not an ideal solution but reasonable in my use case:

use lazy_static or const data (in my situation the data wasn't const'able per the example in the question)

impl Country {
  fn language() -> '&static Language { // my language is more complex than just a simple type described in this question so i do want to have static instances . understandably in the answer it seems overkill
     match self {
        USA => {
          lazy_static! {
             let lang: Language = Language::English; /// in reality more data here...
          }
          &lang
        }
        France => { ...}
        // ... more countries
     }
  }
}