organicomplex 0.7.0

Interactive complex-valued cellular automaton on 2D and 3D grids in search of that stuff - emergence, open-endedness, organicity etc.
use serde::{
    Deserialize,
    Serialize
};

use std::fs::{
    self,
    File
};

use crate::{
    base::PrependErrorString,
    play::automaton::Automaton,
    sys::System
};

const STATE_DIRPATH: &str = "state";
const STATE_FILENAME: &str = "state.json";

/// Save/load of it must be possible...
/// "defaults" allow to add new fields without modifying all saves made before to avoid "missed field" deserialization error
#[derive(Serialize, Deserialize)]
pub struct State {
    #[serde(skip, default="def_automaton")] pub automaton: Option<Automaton>,

    pub playtime: i128, // total play time in microseconds
}

fn def_automaton() -> Option<Automaton> {
    None
}

fn file_exists(filepath: impl ToString) -> bool {
	let filepath = filepath.to_string();
	match File::open(&filepath) {
		Ok(_) => true,
		Err(_) => false
	}
}

impl State {
    pub fn load_or_new_default(sys: &System) -> Result<Self, String> {
        let state_filepath = format!("{}/{}", STATE_DIRPATH, STATE_FILENAME);
        if file_exists(&state_filepath) {
            let json = fs::read(&state_filepath).pre_err(format!("cannot read from '{}'", &state_filepath))?;
            let mut state: Self = serde_json::from_slice(&json).pre_err(format!("cannot deserialize '{}' to state", &state_filepath))?;

            state.automaton = match Automaton::load(STATE_DIRPATH) {
                Ok(automaton) => Some(automaton),
                _ => {
                    Some(Automaton::new_default(sys))
                }
            };

            Ok(state)
        } else {
            Ok(Self{
                automaton: Some(Automaton::new_default(sys)),
                playtime: 0
            })
        }
    }

    pub fn save(&self) -> Result<(), String> {
        fs::create_dir_all(STATE_DIRPATH).unwrap_or(());

        if let Some(automaton) = & self.automaton {
            automaton.save(STATE_DIRPATH)?;
        }

        let state_filepath = format!("{}/{}", STATE_DIRPATH, STATE_FILENAME);
        let json = serde_json::to_vec_pretty(self).pre_err("cannot serialize state")?;
        fs::write(&state_filepath, &json).pre_err(format!("cannot write to '{}'", &state_filepath))?; // no buffering, write all at once

        Ok(())
    }

}