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}