neat_lib 0.1.1

Rust implementation of NeuroEvolution of Augmenting Topologies
Documentation
use crate::neat::*;
use serde_json;
use std::fs::{File, OpenOptions, read_to_string};
use std::io::prelude::*;
use std::io::{BufRead, BufReader};

pub trait Saver<T> {
    fn save(&self, data: &T) -> std::io::Result<()>;
}

pub trait Loader<T> {
    fn load(&self) -> std::io::Result<T>;
}

pub struct FileSaverLoader {
    pub path: String
}

impl FileSaverLoader {
    pub fn new(path: &str) -> Self {
        FileSaverLoader { path: path.to_owned() }
    }
}

impl Saver<population::Population> for FileSaverLoader {
    fn save(&self, population: &population::Population) -> std::io::Result<()> {
        let mut file = OpenOptions::new().create(true).append(true).open(&self.path)?;
        let json = serde_json::to_string(population)?;
        file.write_all(format!("{}\n", json).as_bytes())
            
    }
}

impl Loader<population::Population> for FileSaverLoader {
    fn load(&self) -> std::io::Result<population::Population> {
        let file = File::open(&self.path)?;
        let reader = BufReader::new(file);
        let last_line = reader.lines().fold(None, |acc, line| Some(line.unwrap_or(acc.unwrap_or_default())));
        match last_line {
            Some(line) => Ok(serde_json::from_str(&line)?),
            None => Err(std::io::Error::new(std::io::ErrorKind::Other, "empty file"))
        }
    }
}

impl Loader<config::Config> for FileSaverLoader {
    fn load(&self) -> std::io::Result<config::Config> {
        let data = read_to_string(&self.path)?;
        let config: config::Config = serde_json::from_str(&data)?;
        Ok(config)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_save_load_config_and_population() {
        let config = config::Config::default();
        let population = population::Population::new(&config, "test");
        let saver = FileSaverLoader::new("./tmp/test");
        saver.save(&population).expect("should work");
        let _: population::Population = saver.load().expect("should load");
    }

}