syd-format 0.2.1

binary format for chess game tree
Documentation
use std::{fs::File, io::{Seek, Write, stdout}};
use bulletformat::ChessBoard;
use color_print::cprintln;
mod position;
use std::path::Path;
use filesize::file_real_size_fast;
mod reader;
#[cfg(feature = "hll")]
mod hyperloglog;

#[cfg(feature = "hll")]
#[macro_use] extern crate cfor;
use reader::{
    SydGame
};
mod filter;

#[cfg(any(feature = "positionstats", feature = "readerstats"))]
mod stats;
use filter::Filter;
use std::env;

fn main() -> std::io::Result<()>{
    let args: Vec<String> = env::args().collect();
    let mut filenames: Vec<String> = Vec::<String>::new();
    let mut outfile: String = "data.syd".to_string();
    let mut filter: Filter = Filter::default();
    for arg in &args[1..] {
        if arg.starts_with("--") {
            let mut flag = arg[2..].to_string();
            let mut res: bool = true;
            if flag.starts_with("no-filter") {
                filter = Filter::nofilter();
            }else  {
                if flag.starts_with("no-"){
                    flag = flag[3..].to_string();
                    res = false;
                }
                if flag.starts_with("onlyexact") {
                    filter.require_exact = res;
                }else if flag.starts_with("min_depth") {
                    filter.min_depth = flag.split("=").last().expect("should be").parse::<u8>().unwrap();
                }else if flag.starts_with("min_pieces") {
                    filter.min_pieces = flag.split("=").last().expect("should be").parse::<u32>().unwrap();
                }else if flag.starts_with("max_eval") {
                    filter.max_eval = flag.split("=").last().expect("should be").parse::<u16>().unwrap();
                }else if flag.starts_with("require_bm") {
                    filter.require_bm = res;
                }else if flag.starts_with("filter_check") {
                    filter.filter_check = res;
                }else if flag.starts_with("filter_tactical") {
                    filter.filter_tactical = res;
                }else if flag.starts_with("filter_castling") {
                    filter.filter_castling = res;
                }else if flag.starts_with("out=") {
                    outfile = flag[4..].to_string();
                }else {
                    cprintln!("<red>argument {} unknow</>\n", arg);
                }
            }
        } else {
            filenames.push(arg.to_string());
        }
    }
    cprintln!("<cyan>min_depth</>       = <red>{}</>", filter.min_depth);
    cprintln!("<cyan>min_pieces</>      = <red>{}</>", filter.min_pieces);
    cprintln!("<cyan>max_eval</>        = <red>{}</>", filter.max_eval);
    cprintln!("<cyan>require_exact</>   = <green>{}</>", filter.require_exact);
    cprintln!("<cyan>require_bm</>      = <green>{}</>", filter.require_bm);
    cprintln!("<cyan>filter_check</>    = <green>{}</>", filter.filter_check);
    cprintln!("<cyan>filter_tactical</> = <green>{}</>", filter.filter_tactical);
    cprintln!("<cyan>filter_castling</> = <green>{}</>", filter.filter_castling);
    cprintln!("writing to: <cyan>{}</>", outfile);
    let mut nb_positions = 0;
    let mut nb_batch = 0;
    let mut nb_bytes: usize = 0;
    let mut parser = SydGame::new();
    for filename in filenames {
        cprintln!("parsing file <cyan>{}</>", filename);
        let mut f = File::open(&filename).expect("file not found");
        let filesize = {
            let path = Path::new(&filename);
            let metadata = path.symlink_metadata()?;
            file_real_size_fast(path, &metadata)?
        };
        loop {
            let mut pos = Vec::<ChessBoard>::new();
            match parser.parse_syd(&mut f, &mut pos, &filter) {
                Ok(()) => {}
                Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => break,
                Err(e) => return Err(e)
            }
            nb_positions += pos.len();

            //for p in pos {
            //    stats.update(&p);
            //}
            nb_batch += 1;
            if nb_batch % 1024 == 0 {
                print!("\rProgress: {:.2}", f.stream_position().unwrap() as f64 * 100.0 / filesize as f64);
                stdout().flush().unwrap();
            }
        }
        println!("");
        nb_bytes += f.stream_position().unwrap() as usize;
    }
    println!("numpos = {} num_batch = {} => {:.2} pos/batch", nb_positions, nb_batch, nb_positions as f64 / nb_batch as f64);
    println!("{:.2} B/pos", nb_bytes as f64 / nb_positions as f64);

    #[cfg(feature = "positionstats")]
    parser.posstats.print();
    #[cfg(feature = "readerstats")]
    parser.readerstat.print();
    Ok(())
}