snark_tool/service/io/
reader_g6.rs1use std::str::Chars;
2
3use crate::graph::graph::{Graph, GraphConstructor};
4use crate::service::io::error::ReadError;
5use crate::service::io::reader::GraphFileReader;
6use std::io::{BufRead, BufReader};
7use std::marker::PhantomData;
8use std::{fs, io, result};
9
10pub const BIAS: u8 = 63;
11pub const SMALLN: u64 = 62;
12const WRONG_FORMAT: &str = "Wrong g6 format";
13
14type Result<T> = result::Result<T, ReadError>;
15
16pub struct G6Reader<'a, G>
17where
18 G: Graph,
19{
20 lines: io::Lines<BufReader<&'a fs::File>>,
21 _ph: PhantomData<G>,
22}
23
24impl<'a, G> GraphFileReader<'a, G> for G6Reader<'a, G>
25where
26 G: Graph + GraphConstructor,
27{
28 fn new(file: &'a fs::File) -> Self {
29 G6Reader {
30 lines: io::BufReader::new(file).lines(),
31 _ph: PhantomData,
32 }
33 }
34
35 fn next(&mut self) -> Option<Result<G>> {
36 let line_opt = self.lines.next();
37 match line_opt {
38 None => {
39 return None;
41 }
42 Some(line) => {
43 if let Ok(line_str) = line {
44 if line_str.trim().is_empty() {
45 return self.next();
46 }
47 let graph = G6Reader::read_graph(line_str);
48 return Some(graph);
49 } else {
50 return self.next();
52 }
53 }
54 }
55 }
56}
57
58impl<'a, G> G6Reader<'a, G>
59where
60 G: Graph + GraphConstructor,
61{
62 pub fn read_graph(source: impl AsRef<str>) -> Result<G> {
63 let mut iterator = source.as_ref().chars();
64 let size = get_graph_size(&mut iterator);
65 let graph = G6Reader::create_graph(&mut iterator, size? as u32)?;
66 Ok(graph)
67 }
68
69 fn create_graph(iterator: &mut Chars, size: u32) -> Result<G> {
70 let vertices = size as usize;
71 let edges = (size * 3 / 2) as usize;
72 let mut graph = G::with_capacity(vertices, edges);
73 let mut char = iterator.next();
74 let mut position = Position { row: 0, column: 1 };
75 while char != None {
76 let char_num = G6Reader::<G>::extract_char(char.unwrap())?;
77 let bits = format!("{:b}", char_num);
78 for _i in 0..(6 - bits.len()) {
79 position.increment();
80 }
81 for char in bits.chars() {
82 if char == '1' {
83 graph.add_edge(position.row, position.column);
84 }
85 position.increment();
86 }
87 char = iterator.next();
88 }
89 Ok(graph)
90 }
91
92 fn extract_char(char: char) -> Result<u8> {
93 let char_num = char as u8;
94 if char_num < BIAS || char_num > BIAS * 2 {
95 return Err(ReadError {
96 message: format!(
97 "{} `{}` is not allowed character",
98 WRONG_FORMAT, char_num as char
99 ),
100 });
101 }
102 Ok(char_num - BIAS)
103 }
104}
105
106#[derive(Debug)]
107pub struct Position {
108 pub row: usize,
109 pub column: usize,
110}
111
112impl Position {
113 pub fn increment(&mut self) {
114 if (self.row + 1) == self.column {
115 self.column += 1;
116 self.row = 0;
117 } else {
118 self.row += 1;
119 }
120 }
121}
122
123pub fn get_graph_size(iterator: &mut Chars) -> Result<u64> {
124 let mut char = iterator.next();
125 if char == Some(':') || char == Some('&') {
126 char = iterator.next();
127 }
128
129 if char.is_none() {
130 return Err(ReadError {
131 message: "".to_string(),
132 });
133 }
134
135 let mut size = (char.unwrap() as u64) - BIAS as u64;
136 if size > SMALLN {
137 char = iterator.next();
138 if char.is_none() {
139 return Err(ReadError {
140 message: "".to_string(),
141 });
142 }
143 size = (char.unwrap() as u64) - BIAS as u64;
144
145 if size > SMALLN {
146 char = iterator.next();
147 if char.is_none() {
148 return Err(ReadError {
149 message: "".to_string(),
150 });
151 }
152 size = (char.unwrap() as u64) - BIAS as u64;
153 size = append_char_binary_to_size(size, iterator)?;
154 size = append_char_binary_to_size(size, iterator)?;
155 size = append_char_binary_to_size(size, iterator)?;
156 size = append_char_binary_to_size(size, iterator)?;
157 size = append_char_binary_to_size(size, iterator)?;
158 } else {
159 size = append_char_binary_to_size(size, iterator)?;
160 size = append_char_binary_to_size(size, iterator)?;
161 }
162 }
163 Ok(size)
164}
165
166fn append_char_binary_to_size(mut size: u64, iterator: &mut Chars) -> Result<u64> {
167 let char = iterator.next();
168 if char.is_none() {
169 return Err(ReadError {
170 message: "".to_string(),
171 });
172 }
173 size = (size << 6) | ((char.unwrap() as u64) - BIAS as u64);
174 Ok(size)
175}