simple_file_manager/lib.rs
1/// This is an API for modifying the general data files.
2///
3/// **Author: @_Yunhao Xu_**
4///
5/// **Version: v1.0.0**
6
7pub mod fileapi {
8 use std::fmt::Debug;
9 use std::fs::{File, remove_file};
10 use std::io::{Read, Write};
11 use std::path::Path;
12 use std::str::FromStr;
13
14 /// A structure of file modified API. This class is used to change, read, write, remove a file in the project.
15 ///
16 /// **You can custom the split character by using [split] function.**
17 ///
18 /// To initialize the [FileAPI], you can use the [from] function.
19 ///
20 /// # Example
21 ///
22 /// create a new FileAPI instance:
23 /// ```no_run
24 /// use self::simple_file_manager::fileapi::FileAPI;
25 ///
26 /// let file = FileAPI::from("filename.gph");
27 /// ```
28 ///
29 /// collect a [Reader] type (same with [Builder], [Changer]):
30 /// ```no_run
31 /// use self::simple_file_manager::fileapi::FileAPI;
32 ///
33 /// // custom the split character.
34 /// let file = FileAPI::from("filename.gph").split(',');
35 /// let reader = file.reader();
36 ///
37 /// // read the header of the file
38 /// let header = reader.read_header::<usize>(1)[0].clone();
39 ///
40 /// assert_eq!(header, vec![1, 2, 3]);
41 ///
42 /// ```
43 /// then you will receive a [Vec] recording the value in the first line, which are also parsed to [usize] type.
44 ///
45 /// [split]: FileAPI::split
46 /// [from]: FileAPI::from
47 pub struct FileAPI {
48 pub path: String,
49 split: char
50 }
51
52 impl FileAPI {
53 /// Initialize the [FileAPI], you can use the [from] function.
54 /// # Example
55 ///
56 /// create a new FileAPI instance:
57 /// ```no_run
58 /// use self::simple_file_manager::fileapi::FileAPI;
59 ///
60 /// let file = FileAPI::from("filename.gph");
61 /// ```
62 pub fn from(path: &str) -> FileAPI {
63 FileAPI {
64 path: path.to_string(),
65 split: ' '
66 }
67 }
68
69 /// Set the split character for all process (except [read_csv]). The default character is ' ' (whitespace).
70 /// # Example
71 ///
72 /// ```no_run
73 /// use self::simple_file_manager::fileapi::FileAPI;
74 ///
75 /// let file = FileAPI::from("filename.gph").split(',');
76 /// // the values will divided by ','.
77 /// let reader = file.reader();
78 /// let body = reader.read_body::<usize>(1, 1);
79 ///
80 /// assert_eq!(body, vec![vec![4, 5, 6], vec![7, 8, 9]]);
81 /// ```
82 ///
83 /// [read_csv]: Reader::read_csv
84 pub fn split(mut self, split: char) -> Self {
85 self.split = split.clone();
86 self
87 }
88
89 /// Get a Reader object for reading several values of the same file in succession.
90 ///
91 /// # Example
92 /// collect a [Reader] type (same with [Builder], [Changer]):
93 /// ```no_run
94 /// use self::simple_file_manager::fileapi::FileAPI;
95 ///
96 /// let file = FileAPI::from("filename.gph");
97 /// let reader = file.reader();
98 ///
99 /// // read the header of the file
100 /// let header = reader.read_header::<usize>(1)[0].clone();
101 ///
102 /// assert_eq!(header, vec![1, 2, 3]);
103 /// ```
104 /// then you will receive a [Vec] recording the value in the first line, which are also parsed to [usize] type.
105 pub fn reader(&self) -> Reader {
106 Reader::from(self)
107 }
108
109 /// Get a Changer object for modifying several values of the same file in succession.
110 ///
111 /// # Example
112 /// collect a [Changer] type (same with [Builder], [Reader]):
113 /// ```no_run
114 /// use self::simple_file_manager::fileapi::FileAPI;
115 ///
116 /// let file = FileAPI::from("filename.gph").split(',');
117 /// let changer = file.changer();
118 ///
119 /// // change the value in the 2th line and 2th row to value '123':
120 /// // you can consecutive change values:
121 /// changer.change_value(2, 2, "123")
122 /// .change_value(3, 2, "567")
123 /// .change_value(4, 2, "560")
124 /// .execute(); // after modifying the value, you will need to execute your changes.
125 /// ```
126 pub fn changer(&self) -> Changer {
127 Changer::from(self)
128 }
129
130 /// Get a Builder object for writing several values for a new file in succession.
131 ///
132 /// # Example
133 /// collect a [Builder] type (same with [Changer], [Reader]):
134 /// ```no_run
135 /// use self::simple_file_manager::fileapi::FileAPI;
136 ///
137 /// let file = FileAPI::from("filename.gph");
138 /// let mut builder = file.builder();
139 ///
140 /// // write a line:
141 /// // you can consecutive write lines:
142 /// builder.write_line("This is the second line.")
143 /// .write_line("This is the third line.")
144 /// .write_line("This is the forth line.")
145 /// .execute(); // you will also need to execute your changes:
146 ///
147 /// ```
148 pub fn builder(&self) -> Builder {
149 Builder::from(self)
150 }
151
152 /// A function to remove the file and delete the object.
153 ///
154 /// # Example
155 ///
156 /// ```no_run
157 /// use self::simple_file_manager::fileapi::FileAPI;
158 ///
159 /// FileAPI::from("filename.gph").remove();
160 /// ```
161 pub fn remove(&self) {
162 remove_file(self.path.clone()).unwrap();
163 }
164
165 /// A function to check if the file exist.
166 ///
167 /// # Example
168 ///
169 /// ```no_run
170 /// use self::simple_file_manager::fileapi::FileAPI;
171 ///
172 /// let file = FileAPI::from("filename.gph");
173 /// if file.is_exist() {
174 /// file.remove();
175 /// };
176 /// ```
177 pub fn is_exist(&self) -> bool {
178 Path::new(&self.path).exists()
179 }
180 }
181
182 impl Clone for FileAPI {
183 fn clone(&self) -> Self {
184 FileAPI {
185 path: self.path.clone(),
186 split: self.split.clone()
187 }
188 }
189 }
190
191 /// A reader structure for reading specific values of the same file in succession.
192 ///
193 /// # Example
194 /// collect a [Reader] type (same with [Builder], [Changer]):
195 /// ```no_run
196 /// use self::simple_file_manager::fileapi::FileAPI;
197 ///
198 /// let file = FileAPI::from("filename.gph");
199 /// let reader = file.reader();
200 ///
201 /// // read the header of the file
202 /// let header = reader.read_header::<usize>(1)[0].clone();
203 ///
204 /// assert_eq!(header, vec![1, 2, 3]);
205 /// ```
206 /// then you will receive a [Vec] recording the value in the first line, which are also parsed to [usize] type.
207 pub struct Reader<'a> {
208 pub lines: String,
209 file: &'a FileAPI,
210 pub values: Vec<String>
211 }
212
213 impl Reader<'_> {
214 fn from(file: &FileAPI) -> Reader<'_> {
215 let mut the_file = File::open(&file.path).unwrap();
216 let mut lines = String::new();
217 let _ = the_file.read_to_string(&mut lines).unwrap();
218 Reader { lines, file , values: Vec::new()}
219 }
220
221 /// Read all text in the file.
222 ///
223 /// # Example
224 /// collect a [Reader] type (same with [Builder], [Changer]):
225 /// ```no_run
226 /// use self::simple_file_manager::fileapi::FileAPI;
227 ///
228 /// let file = FileAPI::from("filename.gph");
229 /// let reader = file.reader();
230 ///
231 /// // read all the lines in the file
232 /// let context = reader.read_to_string();
233 ///
234 /// assert_eq!(context, String::from("1,2,3\n4,5,6\n7,8,9\n10,12"))
235 /// ```
236 pub fn read_to_string(&self) -> String {
237 self.lines.to_string()
238 }
239
240 /// A function to read a value in this data storage file.
241 ///
242 /// # Example
243 /// collect a [Reader] type (same with [Builder], [Changer]):
244 /// ```no_run
245 /// use self::simple_file_manager::fileapi::FileAPI;
246 ///
247 /// let file = FileAPI::from("filename.gph").split(',');
248 /// let reader = file.reader();
249 ///
250 /// // read the value in the 5th line and 7th row :
251 /// // you can consecutive read values:
252 /// let results = reader.read_value(1, 2)
253 /// .read_value(3, 2)
254 /// .read_value(2, 1)
255 /// .execute::<usize>(); // after select the values, you will need to execute and receive the values stored in a [Vec].
256 ///
257 /// assert_eq!(results, vec![2, 8, 4]);
258 /// ```
259 pub fn read_value(mut self, line:usize, row:usize) -> Self {
260 let a_line = self.lines
261 .lines()
262 .collect::<Vec<&str>>()[line-1]
263 .split(self.file.split.clone())
264 .collect::<Vec<&str>>();
265 self.values.push(a_line[row - 1].to_string());
266 self
267 }
268
269 /// Confirm and receive the selected values.
270 ///
271 /// # Example
272 /// collect a [Reader] type (same with [Builder], [Changer]):
273 /// ```no_run
274 /// use self::simple_file_manager::fileapi::FileAPI;
275 ///
276 /// let file = FileAPI::from("filename.gph").split(',');
277 /// let reader = file.reader();
278 ///
279 /// // read the value in the 5th line and 7th row :
280 /// // you can consecutive read values:
281 /// let results = reader.read_value(1, 2)
282 /// .read_value(3, 2)
283 /// .read_value(2, 1)
284 /// .execute::<usize>(); // after select the values, you will need to execute and receive the values stored in a [Vec].
285 ///
286 /// assert_eq!(results, vec![2, 8, 4]);
287 /// ```
288 pub fn execute<T: FromStr>(&self) -> Vec<T>
289 where
290 <T as FromStr>::Err: Debug,
291 {
292 self.values.iter().map(|v| v.trim().parse::<T>().unwrap()).collect::<Vec<T>>()
293 }
294
295 /// Read the specific lines of header and parse them into a certain type.
296 ///
297 /// # Example
298 /// collect a [Reader] type (same with [Builder], [Changer]):
299 /// ```no_run
300 /// use self::simple_file_manager::fileapi::FileAPI;
301 ///
302 /// let file = FileAPI::from("filename.gph");
303 /// let reader = file.reader();
304 ///
305 /// // read the header of the file
306 /// let header = reader.read_header::<usize>(1)[0].clone();
307 ///
308 /// assert_eq!(header, vec![1, 2, 3]);
309 /// ```
310 /// then you will receive a [Vec] recording the value in the first line, which are also parsed to [usize] type.
311 pub fn read_header<T: FromStr>(&self, len: usize) -> Vec<Vec<T>>
312 where
313 <T as FromStr>::Err: Debug,
314 {
315 if len < 1 {
316 panic!("The 'len' parameter should not less than 1.")
317 }
318 let mut reader = self.lines.lines();
319 let mut header: Vec<Vec<T>> = Vec::new();
320 for _ in 0..len {
321 let line: Vec<T> = Self::read_line_parse(reader.next().unwrap(), self.file.split);
322 header.push(line);
323 }
324 header
325 }
326
327 /// Read the last line and parse them into a certain type.
328 ///
329 /// # Example
330 /// collect a [Reader] type (same with [Builder], [Changer]):
331 /// ```no_run
332 /// use self::simple_file_manager::fileapi::FileAPI;
333 ///
334 /// let file = FileAPI::from("filename.gph");
335 /// let reader = file.reader();
336 ///
337 /// // read the footer of the file
338 /// let footer = reader.read_footer::<usize>();
339 ///
340 /// assert_eq!(footer, vec![10, 12]);
341 /// ```
342 /// then you will receive a [Vec] recording the value in the last line, which are also parsed to [usize] type.
343 pub fn read_footer<T: FromStr>(&self) -> Vec<T>
344 where
345 <T as FromStr>::Err: Debug,
346 {
347 Self::read_line_parse(self.lines.lines().last().unwrap(), self.file.split)
348 }
349
350 /// Read the main context and parse them into a certain type.
351 ///
352 /// # Example
353 /// collect a [Reader] type (same with [Builder], [Changer]):
354 /// ```no_run
355 /// use self::simple_file_manager::fileapi::FileAPI;
356 ///
357 /// let file = FileAPI::from("filename.gph");
358 /// let reader = file.reader();
359 ///
360 /// // read the body
361 /// // skip the first two line and the last line.
362 /// let body = reader.read_body::<usize>(1, 1);
363 ///
364 /// assert_eq!(body, vec![vec![4, 5, 6], vec![7, 8, 9]]);
365 /// ```
366 /// Then you will receive a [Vec<Vec<usize>>] recording the value in the body, which are also parsed to [usize] type.
367 pub fn read_body<T: FromStr>(&self, header: usize, footer: usize) -> Vec<Vec<T>>
368 where
369 <T as FromStr>::Err: Debug,
370 {
371 let mut reader = self.lines.lines();
372 let len = reader.clone().count();
373 let mut context: Vec<Vec<T>> = Vec::new();
374 for i in 0..len - footer {
375 if i < header {
376 reader.next();
377 continue;
378 }
379 let line: Vec<T> = Self::read_line_parse(reader.next().unwrap(), self.file.split);
380 context.push(line);
381 }
382 context
383 }
384
385 // read a line and parse them into certain type.
386 fn read_line_parse<T: FromStr>(line: &str, split: char) -> Vec<T>
387 where
388 <T as FromStr>::Err: Debug,
389 {
390 line.split(split)
391 .collect::<Vec<&str>>()
392 .iter()
393 .map(|s| s.trim().parse::<T>().unwrap())
394 .collect::<Vec<T>>()
395 }
396
397 /// Count the lines.
398 ///
399 /// # Example
400 /// ```no_run
401 /// use self::simple_file_manager::fileapi::FileAPI;
402 ///
403 /// let len = FileAPI::from("filename.gph").reader().count_lines();
404 ///
405 /// assert_eq!(len, 4);
406 /// ```
407 pub fn count_lines(&self) -> usize {
408 self.lines.lines().count()
409 }
410
411 /// A function to read the specific row in this csv file.
412 ///
413 /// # Example
414 /// ```no_run
415 /// use self::simple_file_manager::fileapi::FileAPI;
416 ///
417 /// // read the specific row of the csv file.
418 /// let row = FileAPI::from("filename.gph").reader().read_csv::<usize>(5);
419 ///
420 /// assert_eq!(row, vec![4, 7, 10]);
421 /// ```
422 /// Then you will receive a [Vec] recording the data in this row, which are also parsed to [usize] type.
423 pub fn read_csv<T: FromStr>(&self, row: usize) -> Vec<T>
424 where
425 <T as FromStr>::Err: Debug,
426 {
427 let mut reader = self.lines.lines();
428 reader.next();
429 let data: Vec<T> = reader.map(|l| {
430 l.split(',')
431 .collect::<Vec<&str>>()[row-1]
432 .parse::<T>()
433 .unwrap()
434 }).collect();
435 data
436 }
437 }
438
439 /// A changer structure for change some specific values in the file in succession.
440 ///
441 /// # Example
442 /// collect a [Changer] type (same with [Builder], [Reader]):
443 /// ```no_run
444 /// use self::simple_file_manager::fileapi::FileAPI;
445 ///
446 /// let file = FileAPI::from("filename.gph");
447 /// let changer = file.changer();
448 ///
449 /// // change the value in the 1th line and 2th row to value '123':
450 /// // you can consecutive change values:
451 /// changer.change_value(1, 2, "234")
452 /// .change_value(2, 2, "567")
453 /// .change_value(3, 2, "560")
454 /// .execute(); // after modifying the value, you will need to execute your changes.
455 /// ```
456 pub struct Changer<'a> {
457 lines: Vec<String>,
458 file: &'a FileAPI
459 }
460
461 impl Changer<'_> {
462 fn from(file: &FileAPI) -> Changer<'_> {
463 let mut the_file = File::open(&file.path).unwrap();
464 let mut lines = String::new();
465 let _ = the_file.read_to_string(&mut lines).unwrap();
466 let lines = lines.lines().collect::<Vec<&str>>().iter().map(|l| l.to_string()).collect();
467 Changer { lines, file }
468 }
469
470 /// A function to change a value in this data storage file.
471 ///
472 /// # Example
473 /// collect a [Changer] type (same with [Builder], [Reader]):
474 /// ```no_run
475 /// use self::simple_file_manager::fileapi::FileAPI;
476 ///
477 /// let file = FileAPI::from("filename.gph");
478 /// let changer = file.changer();
479 ///
480 /// // change the value in the 1th line and 2th row to value '123':
481 /// // you can consecutive change values:
482 /// changer.change_value(1, 2, "234")
483 /// .change_value(2, 2, "567")
484 /// .change_value(3, 2, "560")
485 /// .execute(); // after modifying the value, you will need to execute your changes.
486 /// ```
487 pub fn change_value(mut self, line: usize, row: usize, value: &str) -> Self {
488 let a_line = self.lines[line-1].clone();
489 let mut a_line = a_line.split(self.file.split.clone())
490 .collect::<Vec<&str>>();
491 a_line[row-1] = value;
492 self.lines[line-1] = a_line.join(&*self.file.split.to_string());
493 self
494 }
495
496 /// Confirm and implement the changes.
497 ///
498 /// # Example
499 /// collect a [Changer] type (same with [Builder], [Reader]):
500 /// ```no_run
501 /// use self::simple_file_manager::fileapi::FileAPI;
502 ///
503 /// let file = FileAPI::from("filename.gph");
504 /// let changer = file.changer();
505 ///
506 /// // change the value in the 1th line and 2th row to value '123':
507 /// // you can consecutive change values:
508 /// changer.change_value(1, 2, "234")
509 /// .change_value(2, 2, "567")
510 /// .change_value(3, 2, "560")
511 /// .execute(); // after modifying the value, you will need to execute your changes.
512 /// ```
513 pub fn execute(&self) -> &FileAPI {
514 let mut file = File::create(&self.file.path).unwrap();
515 for line in &self.lines {
516 writeln!(file, "{}", line).unwrap();
517 }
518 self.file
519 }
520 }
521
522 /// A changer class for for writing several values for a new file in succession.
523 ///
524 /// # Example
525 /// collect a [Builder] type (same with [Changer], [Reader]):
526 /// ```no_run
527 /// use self::simple_file_manager::fileapi::FileAPI;
528 ///
529 /// let file = FileAPI::from("filename.gph");
530 /// let mut builder = file.builder();
531 ///
532 /// // write a line:
533 /// // you can consecutive write lines:
534 /// builder.write_line("This is the second line.")
535 /// .write_line("This is the third line.")
536 /// .write_line("This is the forth line.")
537 /// .execute(); // you will also need to execute your changes:
538 ///
539 /// ```
540 pub struct Builder<'a> {
541 lines: Vec<String>,
542 file: &'a FileAPI
543 }
544 impl Builder<'_> {
545 fn from(file: &FileAPI) -> Builder<'_> {
546 Builder {
547 lines: Vec::new(),
548 file
549 }
550 }
551
552 /// A function to write a new line in the new file.
553 ///
554 /// # Example
555 /// collect a [Builder] type (same with [Changer], [Reader]):
556 /// ```no_run
557 /// use self::simple_file_manager::fileapi::FileAPI;
558 ///
559 /// let file = FileAPI::from("filename.gph");
560 /// let mut builder = file.builder();
561 ///
562 /// // write a line:
563 /// // you can consecutive write lines:
564 /// builder.write_line("This is the second line.")
565 /// .write_line("This is the third line.")
566 /// .write_line("This is the forth line.")
567 /// .execute(); // you will also need to execute your changes:
568 ///
569 /// ```
570 pub fn write_line(mut self, line: &str) -> Self {
571 self.lines.push(line.to_string());
572 self
573 }
574
575 /// Confirm and implement.
576 ///
577 /// # Example
578 /// collect a [Builder] type (same with [Changer], [Reader]):
579 /// ```no_run
580 /// use self::simple_file_manager::fileapi::FileAPI;
581 ///
582 /// let file = FileAPI::from("filename.gph");
583 /// let mut builder = file.builder();
584 ///
585 /// // write a line:
586 /// // you can consecutive write lines:
587 /// builder.write_line("This is the second line.")
588 /// .write_line("This is the third line.")
589 /// .write_line("This is the forth line.")
590 /// .execute(); // you will also need to execute your changes:
591 ///
592 /// ```
593 pub fn execute(&self) -> &FileAPI {
594 let mut file = File::create(&self.file.path).unwrap();
595 for line in &self.lines {
596 writeln!(file, "{}", line).unwrap();
597 }
598 self.file
599 }
600 }
601}