monorepo/kifu/core/src/database.rs

96 lines
2.8 KiB
Rust
Raw Normal View History

use std::{ffi::OsStr, io::Read, os::unix::ffi::OsStrExt, path::PathBuf};
use sgf::{go, parse_sgf, Game};
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<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Error::IOError(err)
}
}
#[derive(Debug)]
pub struct Database {
path: PathBuf,
games: Vec<go::Game>,
}
impl Database {
pub fn open_path(path: PathBuf) -> Result<Database, Error> {
let mut games: Vec<go::Game> = 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();
for sgf in parse_sgf(&buffer).unwrap() {
match sgf {
Game::Go(game) => games.push(game),
Game::Unsupported(_) => {}
}
}
}
}
Err(err) => println!("failed entry: {:?}", err),
}
}
Ok(Database { path, games })
}
pub fn len(&self) -> usize {
self.games.len()
}
pub fn all_games(&self) -> impl Iterator<Item = &go::Game> {
self.games.iter()
}
}
#[cfg(test)]
mod test {
use super::*;
use cool_asserts::assert_matches;
use sgf::Date;
#[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_matches!(db.all_games().find(|g| g.info.black_player == Some("Steve".to_owned())),
Some(game) => {
assert_eq!(game.info.black_player, Some("Steve".to_owned()));
assert_eq!(game.info.white_player, Some("Savanni".to_owned()));
assert_eq!(game.info.date, vec![Date::Date(chrono::NaiveDate::from_ymd_opt(2023, 4, 19).unwrap())]);
assert_eq!(game.info.komi, Some(6.5));
}
);
}
}