snark-tool 0.4.0

snark-tool library contains structures and algorithm for (mainly) cubic graph analysis
Documentation
use crate::graph::graph::Graph;
use crate::service::io::error::WriteError;
use crate::service::io::reader_g6::{Position, BIAS};
use std::{fs, io, marker, path, result};

type Result<T> = result::Result<T, WriteError>;

pub struct G6Writer<G> {
    _ph: marker::PhantomData<G>,
}

impl<G> G6Writer<G>
where
    G: Graph,
{
    pub fn write_graphs_to_file<P>(
        graphs: &Vec<(G, P)>,
        path: impl AsRef<path::Path>,
    ) -> Result<()> {
        let file_result = fs::OpenOptions::new().create(true).append(true).open(&path);
        if let Err(err) = &file_result {
            return Err(WriteError {
                message: format!("open or create file error: {}", err),
            });
        }
        let mut file = file_result.unwrap();
        for graph in graphs {
            G6Writer::write_graph(&graph.0, &mut file)?;
        }
        Ok(())
    }

    pub fn write_graph(graph: &G, buffer: &mut impl io::Write) -> Result<()> {
        let graph_string = G6Writer::graph_to_g6_string(graph);
        writeln!(buffer, "{}", graph_string)?;
        Ok(())
    }

    pub fn graph_to_g6_string(graph: &G) -> String {
        let mut graph_string = String::new();
        let size = graph.size();
        graph_string.push_str(to_g6_size(size).as_ref());
        let mut position = Position { row: 0, column: 1 };

        let mut binary = String::new();
        loop {
            if graph.has_edge(position.row, position.column) {
                binary.push('1');
            } else {
                binary.push('0');
            }

            if binary.len() == 6 {
                let intval = u8::from_str_radix(binary.as_str(), 2).unwrap();
                graph_string.push((intval + BIAS) as char);
                binary = String::new();
            }
            position.increment();
            if position.row > size || position.column > size {
                break;
            }
        }
        trim_ending_zeros(&mut graph_string);
        graph_string
    }
}

pub fn to_g6_size(size: usize) -> String {
    let mut size_string = String::new();

    if size < 63 {
        size_string.push((size as u8 + BIAS) as char);
        return size_string;
    }
    if size > 62 && size <= 258047 {
        size_string.push_str(to_medium_size_string(size).as_ref());
        return size_string;
    }
    if size > 258047 && size <= 68719476735 {
        size_string.push_str(to_big_size_string(size).as_ref());
        return size_string;
    }
    size_string
}

fn trim_ending_zeros(graph_string: &mut String) {
    loop {
        let char = graph_string.pop();
        if char.is_some() && char.unwrap() != '?' {
            graph_string.push(char.unwrap());
            return;
        }
        if graph_string.is_empty() {
            return;
        }
    }
}

fn to_medium_size_string(mut size: usize) -> String {
    let mut size_string = String::new();
    size_string.push((shift(&mut size) + BIAS) as char);
    size_string.push((shift(&mut size) + BIAS) as char);
    size_string.push((shift(&mut size) + BIAS) as char);
    size_string.push('~');
    revert(size_string)
}

fn to_big_size_string(mut size: usize) -> String {
    let mut size_string = String::new();
    size_string.push((shift(&mut size) + BIAS) as char);
    size_string.push((shift(&mut size) + BIAS) as char);
    size_string.push((shift(&mut size) + BIAS) as char);
    size_string.push((shift(&mut size) + BIAS) as char);
    size_string.push((shift(&mut size) + BIAS) as char);
    size_string.push((shift(&mut size) + BIAS) as char);
    size_string.push('~');
    size_string.push('~');
    revert(size_string)
}

fn revert(mut orig: String) -> String {
    let mut reverted = String::new();
    let mut char = orig.pop();
    while char.is_some() {
        reverted.push(char.unwrap());
        char = orig.pop();
    }
    reverted
}

fn shift(num: &mut usize) -> u8 {
    let orig = num.clone();
    let mut shifted = *num >> 6;
    *num = shifted;
    shifted <<= 6;
    (orig - shifted) as u8
}