use std::{ffi::OsStr, io::Read, os::unix::ffi::OsStrExt, path::PathBuf}; use go_sgf::go::{parse_sgf, GameTree, GameType}; use thiserror::Error; #[derive(Error, Debug)] pub enum Error { #[error("Database permission denied")] PermissionDenied, #[error("An IO error occurred: {0}")] IOError(std::io::Error), } impl From for Error { fn from(err: std::io::Error) -> Self { Error::IOError(err) } } pub struct Database { path: PathBuf, games: Vec, } impl Database { pub fn open_path(path: PathBuf) -> Result { let mut games: Vec = Vec::new(); let extension = PathBuf::from("sgf").into_os_string(); let path_iter = std::fs::read_dir(path.clone())?; for entry in path_iter { match entry { Ok(entry) => { if entry.path().extension() == Some(&extension) { let mut buffer = String::new(); std::fs::File::open(entry.path()) .unwrap() .read_to_string(&mut buffer) .unwrap(); let sgf = parse_sgf(&buffer).unwrap(); games.extend(sgf); } } Err(err) => println!("failed entry: {:?}", err), } } Ok(Database { path, games }) } pub fn all_games(&self) -> impl Iterator { self.games.iter() } } #[cfg(test)] mod test { use super::*; #[test] fn it_reads_empty_database() { let db = Database::open_path(PathBuf::from("fixtures/empty_database/")) .expect("database to open"); assert_eq!(db.all_games().count(), 0); } #[test] fn it_reads_five_games_from_database() { let db = Database::open_path(PathBuf::from("fixtures/five_games/")).expect("database to open"); assert_eq!(db.all_games().count(), 5); for game in db.all_games() { assert_eq!(game.game_type, GameType::Go); } } }