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.
9 //! # use stud_rust_base::io::*;
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>>(())
19 io::{prelude::*, Result},
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.
29 /// Do not use this Trait but rather the `Store` trait.
31 /// Should return the serialized object as a slice of bytes
32 fn data_bytes(&self) -> &[u8];
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.
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];
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) }
52 impl<T: Copy> DataBytes for Vec<T> {
53 fn data_bytes(&self) -> &[u8] {
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) }
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) }
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())
80 impl<T: DataBytes> Store for T {}
81 impl<T> Store for [T] where [T]: DataBytes {}
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;
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)?;
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())?;
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()