1 //! This module contains a few traits and blanket implementations
2 //! for (de)serializing and writing/reading numeric 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::*;
12 //! let head = Vec::<u32>::load_from("head_file_name").expect("could not read head");
13 //! let lat = Vec::<f32>::load_from("node_latitude_file_name").expect("could not read lat");
14 //! head.write_to("output_file").expect("could not write head");
20 use std::io::prelude::*;
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> DataBytesMut for [T] {
53 fn data_bytes_mut(&mut self) -> &mut [u8] {
54 let num_bytes = self.len() * mem::size_of::<T>();
55 unsafe { slice::from_raw_parts_mut(self.as_mut_ptr() as *mut u8, num_bytes) }
59 impl<T: Copy> DataBytesMut for Vec<T> {
60 fn data_bytes_mut(&mut self) -> &mut [u8] {
61 let num_bytes = self.len() * mem::size_of::<T>();
62 unsafe { slice::from_raw_parts_mut(self.as_mut_ptr() as *mut u8, num_bytes) }
66 /// A trait which extends the `DataBytes` trait and exposes a method to write objects to disk.
67 pub trait Store : DataBytes {
68 /// Writes the serialized object to the file with the given filename
69 fn write_to(&self, filename: &str) -> Result<()> {
70 File::create(filename)?.write_all(self.data_bytes())
74 impl<T: DataBytes> Store for T {}
75 impl<T> Store for [T] where [T]: DataBytes {}
77 /// A trait to load serialized data back into objects.
78 pub trait Load : DataBytesMut + Sized {
79 /// This method must create an object of the correct size for serialized data with the given number of bytes.
80 /// It should not be necessary to call this method directly.
81 fn new_with_bytes(num_bytes: usize) -> Self;
83 /// This method will load serialized data from the disk, create an object of the appropriate size,
84 /// deserialize the bytes into the object and return the object.
85 fn load_from(filename: &str) -> Result<Self> {
86 let metadata = fs::metadata(filename)?;
87 let mut file = File::open(filename)?;
89 let mut object = Self::new_with_bytes(metadata.len() as usize);
90 assert_eq!(metadata.len() as usize, object.data_bytes_mut().len());
91 file.read_exact(object.data_bytes_mut())?;
97 impl<T: Default + Copy> Load for Vec<T> {
98 fn new_with_bytes(num_bytes: usize) -> Self {
99 assert_eq!(num_bytes % mem::size_of::<T>(), 0);
100 let num_elements = num_bytes / mem::size_of::<T>();
101 (0..num_elements).map(|_| T::default()).collect()