serde-intermediate 1.6.2

Intermediate representation of Serde serialization
Documentation
use rand::prelude::*;
use serde::{Deserialize, Serialize};
use serde_intermediate::*;
use std::collections::HashMap;

pub trait Generate {
    fn generate<R>(rng: &mut R) -> Self
    where
        R: Rng;
}

#[derive(Debug, Clone, Serialize, Deserialize, ReflectIntermediate)]
pub enum LoginMethod {
    Email {
        user: String,
        domain: String,
        password_hash: u64,
    },
    Google(String),
    Twitter(String),
    Facebook(usize),
}

impl Generate for LoginMethod {
    fn generate<R>(rng: &mut R) -> Self
    where
        R: Rng,
    {
        match rng.random_range::<usize, _>(0..4) {
            0 => {
                let users = ["john", "malkovitch", "rocks"];
                let domains = ["gmail.com", "hotmail.com"];
                Self::Email {
                    user: users.choose(rng).unwrap().to_string(),
                    domain: domains.choose(rng).unwrap().to_string(),
                    password_hash: rng.random(),
                }
            }
            1 => {
                let users = ["john", "malkovitch", "rocks"];
                Self::Google(users.choose(rng).unwrap().to_string())
            }
            2 => {
                let users = ["john", "malkovitch", "rocks"];
                Self::Twitter(users.choose(rng).unwrap().to_string())
            }
            3 => Self::Facebook(rng.random::<u64>() as usize),
            _ => unreachable!(),
        }
    }
}

#[derive(Debug, Default, Clone, Serialize, Deserialize, ReflectIntermediate)]
pub struct Buff {
    multiplier: f32,
    relative: f32,
}

impl Generate for Buff {
    fn generate<R>(rng: &mut R) -> Self
    where
        R: Rng,
    {
        Self {
            multiplier: rng.random_range(0.5..1.5),
            relative: rng.random_range(-2.0..2.0),
        }
    }
}

#[derive(Debug, Default, Clone, Serialize, Deserialize, ReflectIntermediate)]
pub struct Item {
    id: usize,
    buffs: HashMap<String, Buff>,
}

impl Generate for Item {
    fn generate<R>(rng: &mut R) -> Self
    where
        R: Rng,
    {
        let buff_names = ["attack", "defence", "durability"];
        let count = rng.random_range(0..100);
        Self {
            id: rng.random_range(0..5),
            buffs: std::iter::from_fn(|| {
                Some((
                    buff_names.choose(rng).unwrap().to_string(),
                    Buff::generate(rng),
                ))
            })
            .take(count)
            .collect(),
        }
    }
}

#[derive(Debug, Default, Clone, Serialize, Deserialize, ReflectIntermediate)]
pub struct Inventory {
    coins: usize,
    items: Vec<Item>,
}

impl Generate for Inventory {
    fn generate<R>(rng: &mut R) -> Self
    where
        R: Rng,
    {
        let count = rng.random_range(0..50);
        Self {
            coins: rng.random_range(0..1000000),
            items: std::iter::from_fn(|| Some(Item::generate(rng)))
                .take(count)
                .collect(),
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, ReflectIntermediate)]
pub struct Account {
    user_name: String,
    first_name: Option<String>,
    last_name: Option<String>,
    login: LoginMethod,
    inventory: Inventory,
}

impl Generate for Account {
    fn generate<R>(rng: &mut R) -> Self
    where
        R: Rng,
    {
        let user_names = ["abra", "cadabra", "hocus", "pocus"];
        let first_names = ["Adam", "Eve", "Maria", "Neil"];
        let last_names = ["Not", "Great", "Day", "For", "Being", "Creative"];
        Self {
            user_name: user_names.choose(rng).unwrap().to_string(),
            first_name: if rng.random() {
                Some(first_names.choose(rng).unwrap().to_string())
            } else {
                None
            },
            last_name: if rng.random() {
                Some(last_names.choose(rng).unwrap().to_string())
            } else {
                None
            },
            login: LoginMethod::generate(rng),
            inventory: Inventory::generate(rng),
        }
    }
}