snark_tool/procedure/basic_procedures/
read.rs1use crate::graph::graph::{Graph, GraphConstructor};
2use crate::graph::undirected::UndirectedGraph;
3use crate::procedure::error::Error;
4use crate::procedure::helpers::config_helper;
5use crate::procedure::procedure::{GraphProperties, Procedure, Result};
6use crate::procedure::procedure_builder::{ConfigMap, ProcedureBuilder};
7use crate::service::io::error::ReadError;
8use crate::service::io::reader::GraphFileReader;
9use crate::service::io::reader_ba::BaReader;
10use crate::service::io::reader_g6::G6Reader;
11use crate::service::io::reader_json::JsonReader;
12use crate::service::io::reader_s6::S6Reader;
13use std::collections::HashMap;
14use std::{fs, marker, path};
15
16const FILE_NAME: &str = "file";
18const GRAPH_FORMAT: &str = "graph-format";
19const NUMBER_OF_GRAPHS: &str = "number-of-graphs";
20
21pub const G6_FORMAT: &str = "g6";
23pub const S6_FORMAT: &str = "s6";
24pub const BA_FORMAT: &str = "ba";
25pub const JSON_FORMAT: &str = "json";
26
27const DEFAULT_FILE_NAME: &str = "read-procedure-input-file.g6";
28
29struct ReadProcedure<G: Graph> {
30 config: ReadProcedureConfig,
31 _ph: marker::PhantomData<G>,
32}
33
34impl<G: UndirectedGraph + GraphConstructor> Procedure<G> for ReadProcedure<G> {
35 fn run(&self, graphs: &mut Vec<(G, GraphProperties)>) -> Result<()> {
36 println!("running read procedure");
37 self.read_graphs(graphs)
38 }
39}
40
41impl<G: UndirectedGraph + GraphConstructor> ReadProcedure<G> {
42 pub fn read_graphs(&self, graphs: &mut Vec<(G, GraphProperties)>) -> Result<()> {
43 let file_path = self.config.file_path();
44 let graphs_count = self.config.number_of_graphs();
45 let file = Self::open_file_to_read(file_path)?;
46 let graph_format = self.config.graph_format();
47
48 match graph_format.as_str() {
49 G6_FORMAT => {
50 let reader = G6Reader::new(&file);
51 Self::read_by_format(reader, graphs, graphs_count)?;
52 }
53 BA_FORMAT => {
54 let reader = BaReader::<G>::new(&file);
55 Self::read_by_format(reader, graphs, graphs_count)?;
56 }
57 S6_FORMAT => {
58 let reader = S6Reader::<G>::new(&file);
59 Self::read_by_format(reader, graphs, graphs_count)?;
60 }
61 JSON_FORMAT => {
62 Self::read_json_format(graphs, graphs_count, &file)?;
63 }
64 _ => {
65 return Err(Error::ConfigError(String::from(
66 "unknown graph format for read procedure",
67 )));
68 }
69 }
70 Ok(())
71 }
72
73 fn read_by_format<'a, R>(
74 mut reader: R,
75 graphs: &mut Vec<(G, GraphProperties)>,
76 graphs_count: Option<usize>,
77 ) -> Result<()>
78 where
79 R: GraphFileReader<'a, G>,
80 {
81 let mut counter = 1;
82 let mut graph_opt = reader.next();
83 while graph_opt.is_some() {
84 let graph = graph_opt.unwrap()?;
85 let mut properties = GraphProperties::new();
86 properties.insert("size".to_string(), serde_json::to_value(graph.size())?);
87 graphs.push((graph, properties));
88 counter += 1;
89
90 if graphs_count.is_some() && graphs_count.unwrap() < counter {
91 break;
92 }
93 graph_opt = reader.next();
94 }
95 if graphs_count.is_some() && graphs_count.unwrap() > counter {
96 println!(
97 "You asked for: {} graphs but given file contains only {}",
98 graphs_count.unwrap(),
99 counter
100 );
101 }
102 Ok(())
103 }
104
105 fn read_json_format(
106 graphs: &mut Vec<(G, GraphProperties)>,
107 graphs_count: Option<usize>,
108 file: &fs::File,
109 ) -> Result<()> {
110 let mut counter = 1;
111
112 let mut reader = JsonReader::<G>::new(file);
113
114 let mut graph_opt = reader.next_with_properties();
115 while graph_opt.is_some() {
116 let graph = graph_opt.unwrap()?;
117 graphs.push(graph);
118 counter += 1;
119
120 if graphs_count.is_some() && graphs_count.unwrap() < counter {
121 break;
122 }
123
124 graph_opt = reader.next_with_properties();
125 }
126 if graphs_count.is_some() && graphs_count.unwrap() > counter {
127 println!(
128 "You asked for: {} graphs but given file contains only {}",
129 graphs_count.unwrap(),
130 counter
131 );
132 }
133 Ok(())
134 }
135
136 fn open_file_to_read<P: AsRef<path::Path>>(path: P) -> Result<fs::File> {
137 let file_result = fs::OpenOptions::new().read(true).open(&path);
138 if file_result.is_err() {
139 return Err(Error::ReadError(ReadError {
140 message: format!("open file to read error for file: {:?}", path.as_ref()),
141 }));
142 }
143 Ok(file_result.unwrap())
144 }
145}
146
147pub struct ReadProcedureConfig {
148 file_path: String,
149 graph_format: String,
150 number_of_graphs: Option<usize>,
151}
152
153impl ReadProcedureConfig {
154 pub const PROC_TYPE: &'static str = "read";
155
156 pub fn new(file_path: String, graph_format: String, number_of_graphs: Option<usize>) -> Self {
157 ReadProcedureConfig {
158 file_path,
159 graph_format,
160 number_of_graphs,
161 }
162 }
163
164 pub fn default() -> Self {
165 Self {
166 file_path: DEFAULT_FILE_NAME.to_string(),
167 graph_format: GRAPH_FORMAT.to_string(),
168 number_of_graphs: None,
169 }
170 }
171
172 pub fn from_proc_config(config: &HashMap<String, serde_json::Value>) -> Result<Self> {
173 let file_path = config_helper::resolve_value_or_default(
174 &config,
175 FILE_NAME,
176 DEFAULT_FILE_NAME.to_string(),
177 Self::PROC_TYPE,
178 )?;
179 let graph_format = config_helper::resolve_value_or_default(
180 &config,
181 GRAPH_FORMAT,
182 G6_FORMAT.to_string(),
183 Self::PROC_TYPE,
184 )?;
185 let number_of_graphs = config_helper::resolve_value_or_default(
186 &config,
187 NUMBER_OF_GRAPHS,
188 None,
189 Self::PROC_TYPE,
190 )?;
191 let result = ReadProcedureConfig {
192 file_path,
193 graph_format,
194 number_of_graphs,
195 };
196 Ok(result)
197 }
198
199 pub fn file_path(&self) -> &String {
200 &self.file_path
201 }
202
203 pub fn graph_format(&self) -> &String {
204 &self.graph_format
205 }
206
207 pub fn number_of_graphs(&self) -> Option<usize> {
208 self.number_of_graphs
209 }
210}
211
212pub struct ReadProcedureBuilder {}
213
214impl<G: UndirectedGraph + GraphConstructor + 'static> ProcedureBuilder<G> for ReadProcedureBuilder {
215 fn build_from_map(&self, config: ConfigMap) -> Result<Box<dyn Procedure<G>>> {
216 let proc_config = ReadProcedureConfig::from_proc_config(&config)?;
217 Ok(Box::new(ReadProcedure {
218 config: proc_config,
219 _ph: marker::PhantomData,
220 }))
221 }
222}
223
224impl ReadProcedureBuilder {
225 pub fn build<G: UndirectedGraph + GraphConstructor + 'static>(
226 config: ReadProcedureConfig,
227 ) -> Box<dyn Procedure<G>> {
228 Box::new(ReadProcedure {
229 config,
230 _ph: marker::PhantomData,
231 })
232 }
233}