Serialized - Deserialize enum manually

enum Debug Display new

How to create a new instance of an enum from a string and how to convert the enum instance to a string?

In this example we have a very simple enum called Animal that has 3 variants:

enum Animal {
    Cat,
    Dog,
    Fish,
}

We derived it from Debug using the following line in order to allow us to print the value of an instance using the {:?} debugging format. (Or the dbg! macro for that matter.)

#[derive(Debug)]

So we can write this:

println!("{c:?}");

Converting string to enum variant

We wanted to be able to write something like this and let it return Animal::Cat:

let c = Animal::new("cat");

For this we implemented the new method for the Animal enum and mapped each string to the appropriate variant.

This mapping allows us to accept alternatives. For example, I included both "dog" and "hound" to be mapped to "Animal::Dog".

As we are using match on an &str string Rust forces us to have an "arm" for each possible value, so we have to provide a catch-all default case. We could return "Animal::Dog" or any other variant as the default, but here we elected to panic!.

impl Animal {
    fn new(text: &str) -> Self {
        match text {
            "cat" => Animal::Cat,
            "dog" => Animal::Dog,
            "fish"  => Animal::Fish,

            "hound" => Animal::Dog,

            // default is required
            _ => panic!("No such animal as {text:?}"),
        }
    }
}

Convert enum variant to string

We also want to be able to convert the variant to a string in order to be able to use this:

println!("{c}");

For this we need to implement the Display trait mapping each variant to the string to display:

impl std::fmt::Display for Animal {
    fn fmt(&self, format: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let text = match self {
            Animal::Cat => "cat",
            Animal::Dog => "dog",
            Animal::Fish => "fish",
        };
        write!(format, "{text}")
    }
}

Full example

examples/serialize-deserialize-enum-manually/src/main.rs

#[derive(Debug)]
enum Animal {
    Cat,
    Dog,
    Fish,
}

impl Animal {
    fn new(text: &str) -> Self {
        match text {
            "cat" => Animal::Cat,
            "dog" => Animal::Dog,
            "fish"  => Animal::Fish,

            "hound" => Animal::Dog,

            // default is required
            _ => panic!("No such animal as {text:?}"),
        }
    }
}

impl std::fmt::Display for Animal {
    fn fmt(&self, format: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let text = match self {
            Animal::Cat => "cat",
            Animal::Dog => "dog",
            Animal::Fish => "fish",
        };
        write!(format, "{text}")
    }
}

fn main() {
    let c = Animal::new("cat");
    println!("{c:?}");
    println!("{c}");

    let d = Animal::new("hound");
    println!("{d}");

    let m = Animal::new("mouse");
    println!("{m}");
}


Author

Gabor Szabo (szabgab)

Gabor Szabo, the author of the Rust Maven web site maintains several Open source projects in Rust and while he still feels he has tons of new things to learn about Rust he already offers training courses in Rust and still teaches Python, Perl, git, GitHub, GitLab, CI, and testing.

Gabor Szabo