Rust does the correct, sane, thing: but why - and how?

I have an enum that mixes i64s, NaiveDates, bytes (Vec), and Strings, yet rust is able to sort these all sanely.

use chrono::prelude::*;

fn main() {
    let mut v: Vec<Value> = vec![
        5.into(),
        "def".as_bytes().to_vec().into(),
        (-17).into(),
        "x".into(),
        NaiveDate::from_ymd(2020, 11, 2).into(),
        "A".into(),
        0.into(),
        "bbc".as_bytes().to_vec().into(),
        "ab".into(),
        NaiveDate::from_ymd(1920, 10, 1).into(),
    ];
    println!("{:?}", &v);
    v.sort_unstable();
    println!("{:?}", &v);
}

#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
pub enum Value {
    Bytes(Vec<u8>),
    Date(NaiveDate),
    Int(i64),
    Str(String),
}

impl From<Vec<u8>> for Value {
    fn from(b: Vec<u8>) -> Self {
        Value::Bytes(b)
    }
}

impl From<NaiveDate> for Value {
    fn from(d: NaiveDate) -> Self {
        Value::Date(d)
    }
}

impl From<i64> for Value {
    fn from(i: i64) -> Self {
        Value::Int(i)
    }
}

impl From<&str> for Value {
    fn from(s: &str) -> Self {
        Value::Str(s.to_string())
    }
}

impl From<String> for Value {
    fn from(s: String) -> Self {
        Value::Str(s)
    }
}

Output:

[Int(5), Bytes([100, 101, 102]), Int(-17), Str("x"), Date(2020-11-02), Str("A"), Int(0), Bytes([98, 98, 99]), Str("ab"), Date(1920-10-01)]
[Bytes([98, 98, 99]), Bytes([100, 101, 102]), Date(1920-10-01), Date(2020-11-02), Int(-17), Int(0), Int(5), Str("A"), Str("ab"), Str("x")]

It is possible to see the code that Rust has generated to do this?

Those #[derive(...)] are macro that actually generates Rust code at the early stage of compilation. You can expand those macros with tools like cargo-expand, but the Rust playground also supports it.

Click the [TOOLS] button at the top right corner and click Expand Macros. I've stripped the code to reduce output.

4 Likes

Thanks, that's just what I needed!