logs.rs 2.21 KB
Newer Older
Bharat Garhewal's avatar
Cleanup    
Bharat Garhewal committed
1
use crate::automatadefs::mealy::{InputSymbol, OutputSymbol};
2
3
use itertools::Itertools;
use std::{
Bharat Garhewal's avatar
Bharat Garhewal committed
4
    collections::HashMap,
5
6
7
8
9
    fs::{canonicalize, File},
    io::{self, BufRead},
    path::Path,
};

Bharat Garhewal's avatar
Cleanup    
Bharat Garhewal committed
10
pub type Logs = Vec<(Box<[InputSymbol]>, Box<[OutputSymbol]>)>;
11
12
13
14
15

/// Read the logs in a vector, see [`Logs`].
///
/// # Errors
/// If file at `file_path` cannot be read.
Bharat Garhewal's avatar
Bharat Garhewal committed
16
pub fn read<S: std::hash::BuildHasher>(
17
    file_path: &str,
Bharat Garhewal's avatar
Bharat Garhewal committed
18
19
    input_map: &HashMap<String, InputSymbol, S>,
    output_map: &HashMap<String, OutputSymbol, S>,
20
21
22
23
24
) -> Result<Logs, Box<dyn std::error::Error>> {
    let log_vec = read_lines(canonicalize(file_path)?)?
        .flatten()
        .skip(1) // The first entry contains the number of traces.
        .into_iter()
Bharat Garhewal's avatar
Bharat Garhewal committed
25
        .map(|line| parse_and_transform_trace(&line, input_map, output_map))
26
27
28
29
        .collect_vec();
    Ok(log_vec)
}

Bharat Garhewal's avatar
Bharat Garhewal committed
30
31
32
33
fn parse_and_transform_trace<S: std::hash::BuildHasher>(
    line: &str,
    input_map: &HashMap<String, InputSymbol, S>,
    output_map: &HashMap<String, OutputSymbol, S>,
Bharat Garhewal's avatar
Cleanup    
Bharat Garhewal committed
34
) -> (Box<[InputSymbol]>, Box<[OutputSymbol]>) {
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    let mut line_split_iter = line.split_whitespace();
    let _ = line_split_iter.next(); // Skip length
    let len_inputs: usize = (line_split_iter
        .next()
        .unwrap()
        .trim()
        .parse::<usize>()
        .expect("Error reading length of a log trace!"))
        / 2; // Skip acceptance
    let (input_vec, output_vec): (Vec<_>, Vec<_>) = line_split_iter
        .batching(|line_split_iter| line_split_iter.next().zip(line_split_iter.next()))
        .filter_map(|(x, y)| input_map.get(x.trim()).zip(output_map.get(y.trim())))
        .unzip();
    assert_eq!(input_vec.len(), len_inputs, "Error while parsing the logs");
    assert_eq!(
        input_vec.len(),
        output_vec.len(),
        "Input and output seqs are not of equal length in the log!"
    );
    (input_vec.into_boxed_slice(), output_vec.into_boxed_slice())
}

/// The output is wrapped in a Result to allow matching on errors.
/// Returns an Iterator to the Reader of the lines of the file.
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
where
    P: AsRef<Path>,
{
    let file = File::open(filename)?;
    Ok(io::BufReader::new(file).lines())
}