more refactoring
[Mitarbeiter/Tim-Zeitz/stud-rust-base.git] / src / io.rs
1 //! This module contains a few traits and blanket implementations
2 //! for (de)serializing and writing/reading data to/from the disc.
3 //! To use it you should import the `Load` and `Store` traits and use the
4 //! `load_from` and `write_to` methods.
5 //!
6 //! # Example
7 //!
8 //! ```no_run
9 //! # use stud_rust_base::io::*;
10 //!
11 //! let head = Vec::<u32>::load_from("head_file_name")?;
12 //! let lat = Vec::<f32>::load_from("node_latitude_file_name")?;
13 //! head.write_to(&"output_file")?;
14 //! # Ok::<(), Box<dyn std::error::Error>>(())
15 //! ```
16
17 use std::{
18     fs::{metadata, File},
19     io::{prelude::*, Result},
20     mem,
21     path::Path,
22     slice,
23 };
24
25 /// A trait which allows accessing the data of an object as a slice of bytes.
26 /// The bytes should represent a serialization of the object and allow
27 /// recreating it when reading these bytes again from the disk.
28 ///
29 /// Do not use this Trait but rather the `Store` trait.
30 pub trait DataBytes {
31     /// Should return the serialized object as a slice of bytes
32     fn data_bytes(&self) -> &[u8];
33 }
34
35 /// A trait which mutably exposes the internal data of an object so that
36 /// a serialized object can be loaded from disk and written back into a precreated
37 /// object of the right size.
38 ///
39 /// Do not use this Trait but rather the `Load` trait.
40 pub trait DataBytesMut {
41     /// Should return a mutable slice of the internal data of the object
42     fn data_bytes_mut(&mut self) -> &mut [u8];
43 }
44
45 impl<T: Copy> DataBytes for [T] {
46     fn data_bytes(&self) -> &[u8] {
47         let num_bytes = self.len() * mem::size_of::<T>();
48         unsafe { slice::from_raw_parts(self.as_ptr() as *const u8, num_bytes) }
49     }
50 }
51
52 impl<T: Copy> DataBytes for Vec<T> {
53     fn data_bytes(&self) -> &[u8] {
54         &self[..].data_bytes()
55     }
56 }
57
58 impl<T: Copy> DataBytesMut for [T] {
59     fn data_bytes_mut(&mut self) -> &mut [u8] {
60         let num_bytes = self.len() * mem::size_of::<T>();
61         unsafe { slice::from_raw_parts_mut(self.as_mut_ptr() as *mut u8, num_bytes) }
62     }
63 }
64
65 impl<T: Copy> DataBytesMut for Vec<T> {
66     fn data_bytes_mut(&mut self) -> &mut [u8] {
67         let num_bytes = self.len() * mem::size_of::<T>();
68         unsafe { slice::from_raw_parts_mut(self.as_mut_ptr() as *mut u8, num_bytes) }
69     }
70 }
71
72 /// A trait which extends the `DataBytes` trait and exposes a method to write objects to disk.
73 pub trait Store: DataBytes {
74     /// Writes the serialized object to the file with the given path
75     fn write_to(&self, path: &dyn AsRef<Path>) -> Result<()> {
76         File::create(path)?.write_all(self.data_bytes())
77     }
78 }
79
80 impl<T: DataBytes> Store for T {}
81 impl<T> Store for [T] where [T]: DataBytes {}
82
83 /// A trait to load serialized data back into objects.
84 pub trait Load: DataBytesMut + Sized {
85     /// This method must create an object of the correct size for serialized data with the given number of bytes.
86     /// It should not be necessary to call this method directly.
87     fn new_with_bytes(num_bytes: usize) -> Self;
88
89     /// This method will load serialized data from the disk, create an object of the appropriate size,
90     /// deserialize the bytes into the object and return the object.
91     fn load_from<P: AsRef<Path>>(path: P) -> Result<Self> {
92         let metadata = metadata(path.as_ref())?;
93         let mut file = File::open(path)?;
94
95         let mut object = Self::new_with_bytes(metadata.len() as usize);
96         assert_eq!(metadata.len() as usize, object.data_bytes_mut().len());
97         file.read_exact(object.data_bytes_mut())?;
98
99         Ok(object)
100     }
101 }
102
103 impl<T: Default + Copy> Load for Vec<T> {
104     fn new_with_bytes(num_bytes: usize) -> Self {
105         assert_eq!(num_bytes % mem::size_of::<T>(), 0);
106         let num_elements = num_bytes / mem::size_of::<T>();
107         (0..num_elements).map(|_| T::default()).collect()
108     }
109 }