ed-journals 0.5.0

Provides models for representing and parsing elite dangerous journal files
Documentation
use std::collections::HashMap;
use serde::Serialize;
use crate::materials::Material;

#[derive(Serialize, Default)]
pub struct MaterialsState {
    pub materials: HashMap<Material, u16>,
}

impl MaterialsState {
    pub fn set_material_count(&mut self, material: Material, count: u16) {
        let count = count.min(material.grade().grade_storage_limit());

        self.materials
            .entry(material)
            .and_modify(|current| *current = count)
            .or_insert(count);
    }

    pub fn add_material_count(&mut self, material: Material, count: u16) {
        self.materials
            .entry(material.clone())
            .and_modify(|current| *current = (*current + count).min(material.grade().grade_storage_limit()))
            .or_insert(count.min(material.grade().grade_storage_limit()));
    }

    pub fn remove_material_count(&mut self, materials: Material, count: u16) {
        self.materials
            .entry(materials.clone())
            .and_modify(|current| *current = current.saturating_sub(count))
            .or_insert(0);
    }

    pub fn get_count(&self, material: &Material) -> u16 {
        let Some(count) = self.materials.get(material) else {
            return 0;
        };

        *count
    }

    pub fn is_full(&self, material: &Material) -> bool {
        let Some(count) = self.materials.get(material) else {
            return false;
        };

        count >= &material.grade().grade_storage_limit()
    }
}

#[cfg(test)]
mod tests {
    use crate::materials::Material;
    use crate::state::models::materials_state::MaterialsState;

    #[test]
    fn material_state_is_modified_correctly() {
        let mut state = MaterialsState::default();

        state.set_material_count(Material::Carbon, 10);
        assert_eq!(state.get_count(&Material::Carbon), 10);

        state.set_material_count(Material::Carbon, 10000);
        assert_eq!(state.get_count(&Material::Carbon), 300);

        state.remove_material_count(Material::Carbon, 20);
        assert_eq!(state.get_count(&Material::Carbon), 280);

        state.remove_material_count(Material::Carbon, 1000);
        assert_eq!(state.get_count(&Material::Carbon), 0);

        state.add_material_count(Material::Carbon, 20);
        assert_eq!(state.get_count(&Material::Carbon), 20);

        state.add_material_count(Material::Carbon, 10);
        assert_eq!(state.get_count(&Material::Carbon), 30);

        state.add_material_count(Material::Carbon, 1000);
        assert_eq!(state.get_count(&Material::Carbon), 300);
    }

    #[test]
    fn set_materials_without_entry_is_done_correctly() {
        let mut state = MaterialsState::default();

        state.set_material_count(Material::Carbon, 10);
        assert_eq!(state.get_count(&Material::Carbon), 10);

        state.set_material_count(Material::Iron, 10000);
        assert_eq!(state.get_count(&Material::Iron), 300);
    }

    #[test]
    fn add_materials_without_entry_is_done_correctly() {
        let mut state = MaterialsState::default();

        state.add_material_count(Material::Carbon, 10);
        assert_eq!(state.get_count(&Material::Carbon), 10);

        state.add_material_count(Material::Iron, 10000);
        assert_eq!(state.get_count(&Material::Iron), 300);
    }

    #[test]
    fn remove_materials_without_entry_is_done_correctly() {
        let mut state = MaterialsState::default();

        state.remove_material_count(Material::Carbon, 10);
        assert_eq!(state.get_count(&Material::Carbon), 0);
    }
}