lazy_db/lazy_data/
reading.rs

1use super::*;
2
3macro_rules! incorrect_type {
4    ($original:expr, $expected:pat) => {
5        if let $expected = $original {}
6        else {
7            return Err(LDBError::IncorrectType($original, stringify!($expected).to_string()));
8        };
9    }
10}
11
12macro_rules! collect_number {
13    (($name:ident) $type:ty = $lazy_type:pat) => {
14        /// ### Expensive Action
15        /// ( Loads the entire file's data into memory  )
16        /// 
17        /// ---
18        /// Collects the `LazyData` as an unsigned integer.
19        /// 
20        /// Returns `LDBError::IncorrectType` if the LazyData type is not the correct unsigned integer
21        pub fn $name(self) -> Result<$type, LDBError> {
22            incorrect_type!(self.lazy_type, $lazy_type);
23
24            // Expensive and best to be avoided if possible
25            let bytes = self.wrapper.read_to_end()?;
26            const LENGTH: usize = <$type>::BITS as usize / 8usize;
27
28            // Check if the size is correct
29            if bytes.len() != LENGTH {
30                return Err(LDBError::InvalidNumberByteLength(bytes.len() as u8,
31                    stringify!($lazy_type).to_string()))
32            };
33
34            // Convert to number
35            let value = <$type>::from_be_bytes(unsafe { *(bytes.as_ptr() as *const [u8; LENGTH]) });
36
37            Ok(value)
38        }
39    };
40
41    (signed ($name:ident) $type:ty = $lazy_type:pat) => {
42        /// ### Expensive Action
43        /// ( Loads the entire file's data into memory  )
44        /// 
45        /// ---
46        /// Collects the `LazyData` as a signed integer.
47        /// 
48        /// Returns `LDBError::IncorrectType` if the LazyData type is not the correct signed integer
49        pub fn $name(self) -> Result<$type, LDBError> {
50            incorrect_type!(self.lazy_type, $lazy_type);
51
52            // Expensive and best to be avoided if possible
53            let bytes = self.wrapper.read_to_end()?;
54            const LENGTH: usize = <$type>::BITS as usize / 8usize;
55
56            // Check if the size is correct
57            if bytes.len() != LENGTH {
58                return Err(LDBError::InvalidNumberByteLength(bytes.len() as u8,
59                    stringify!($lazy_type).to_string()))
60            };
61
62            // Convert to number
63            let value = <$type>::from_be_bytes(unsafe { *(bytes.as_ptr() as *const [u8; LENGTH]) });
64
65            Ok(value)
66        }
67   }
68}
69
70macro_rules! collect_array {
71    (($name:ident) $type:ty = $lazy_type:ident) => {
72        collect_array!(($name, <$type>::BITS as usize / 8usize) $type = $lazy_type);
73    };
74
75    (($name:ident, $bytes:expr) $type:ty = $lazy_type:ident) => {
76        /// ### Expensive Action
77        /// ( Loads the entire file's data into memory  )
78        /// 
79        /// ---
80        /// Collects the `LazyData` as an array of values of a single type
81        /// 
82        /// Returns `LDBError::IncorrectType` if the LazyData type is not the correct array type
83        pub fn $name(mut self) -> Result<Box<[$type]>, LDBError> {
84            incorrect_type!(self.lazy_type, LazyType::Array);
85
86            // Read array-type
87            let array_type =
88                LazyType::try_from(self.wrapper.read(1)?[0])?;
89            incorrect_type!(array_type, LazyType::$lazy_type);
90
91            const LENGTH: usize = $bytes;
92            let mut result = Vec::<$type>::new();
93            loop {
94                let bytes = match self.wrapper.read_opt(LENGTH)? {
95                    Some(x) => x,
96                    None => break,
97                };
98                // Convert to number
99                let value = <$type>::from_be_bytes(unsafe { *(bytes.as_ptr() as *const [u8; LENGTH]) });
100                result.push(value);
101            }
102
103            Ok(result.into_boxed_slice())
104        }
105    };
106}
107
108impl LazyData {
109    /// ### Expensive Action
110    /// ( Reads all of the contents of the file and stores it on the heap )
111    /// 
112    /// ---
113    /// Collects the `LazyData` as a `Box<[u8]>`.
114    /// 
115    /// Returns `LDBError::IncorrectType` if the LazyData type is not `LazyType::Binary`
116    pub fn collect_binary(self) -> Result<Box<[u8]>, LDBError> {
117        incorrect_type!(self.lazy_type, LazyType::Binary);
118        self.wrapper.read_to_end()
119    }
120
121    /// ### Expensive Action
122    /// ( Loads the entire file's data into memory )
123    /// 
124    /// ---
125    /// Collects the `LazyData` as a `String`
126    /// 
127    /// Returns `LDBError::IncorrectType` if LazyData type is not `LazyType::String`
128    /// Returns `LDBError::IOError` if there is an io error while reading file contents
129    pub fn collect_string(self) -> Result<String, LDBError> {
130        incorrect_type!(self.lazy_type, LazyType::String);
131        // Expensive and best to be avoided if possible
132        let bytes = self.wrapper.read_to_end()?;
133        
134        if let Ok(x) = String::from_utf8(bytes.to_vec()) {
135            Ok(x)
136        } else {
137            Err(LDBError::InvalidUTF8String(bytes))
138        }
139    }
140    
141    // Unsigned numbers
142    collect_number!((collect_u8) u8 = LazyType::U8);
143    collect_number!((collect_u16) u16 = LazyType::U16);
144    collect_number!((collect_u32) u32 = LazyType::U32);
145    collect_number!((collect_u64) u64 = LazyType::U64);
146    collect_number!((collect_u128) u128 = LazyType::U128);
147
148    // Signed numbers
149    collect_number!(signed (collect_i8) i8 = LazyType::I8);
150    collect_number!(signed (collect_i16) i16 = LazyType::I16);
151    collect_number!(signed (collect_i32) i32 = LazyType::I32);
152    collect_number!(signed (collect_i64) i64 = LazyType::I64);
153    collect_number!(signed (collect_i128) i128 = LazyType::I128);
154
155    // Arrays
156    collect_array!((collect_u8_array) u8 = U8);
157    collect_array!((collect_u16_array) u16 = U16);
158    collect_array!((collect_u32_array) u32 = U32);
159    collect_array!((collect_u64_array) u64 = U64);
160    collect_array!((collect_u128_array) u128 = U128);
161    collect_array!((collect_i8_array) i8 = I8);
162    collect_array!((collect_i16_array) i16 = I16);
163    collect_array!((collect_i32_array) i32 = I32);
164    collect_array!((collect_i64_array) i64 = I64);
165    collect_array!((collect_i128_array) i128 = I128);
166    collect_array!((collect_f32_array, 4) f32 = F32);
167    collect_array!((collect_f64_array, 8) f64 = F64);
168
169    /* Floating point numbers */
170
171    /// ### Expensive Action
172    /// ( Loads the entire file's data into memory  )
173    /// 
174    /// ---
175    /// Collects the `LazyData` as an `f32`.
176    /// 
177    /// Returns `LDBError::IncorrectType` if the LazyData type is not ``LazyFloat::F32`
178    pub fn collect_f32(self) -> Result<f32, LDBError> {
179        incorrect_type!(self.lazy_type, LazyType::F32);
180
181        // Expensive and best to be avoided if possible
182        let bytes = self.wrapper.read_to_end()?;
183
184        // Check if the size is correct
185        if bytes.len() != 4 {
186            return Err(LDBError::InvalidNumberByteLength(bytes.len() as u8,
187                stringify!($lazy_type).to_string()))
188        };
189
190        // Convert to number
191        let value = f32::from_be_bytes(unsafe { *(bytes.as_ptr() as *const [u8; 4]) });
192
193        Ok(value)
194    }
195
196    /// ### Expensive Action
197    /// ( Loads the entire file's data into memory  )
198    /// 
199    /// ---
200    /// Collects the `LazyData` as an `f64`.
201    /// 
202    /// Returns `LDBError::IncorrectType` if the LazyData type is ``LazyFloatType::F64`
203    pub fn collect_f64(self) -> Result<f64, LDBError> {
204        incorrect_type!(self.lazy_type, LazyType::F64);
205
206        // Expensive and best to be avoided if possible
207        let bytes = self.wrapper.read_to_end()?;
208
209        // Check if the size is correct
210        if bytes.len() != 8 {
211            return Err(LDBError::InvalidNumberByteLength(bytes.len() as u8,
212                stringify!($lazy_type).to_string()))
213        };
214
215        // Convert to number
216        let value = f64::from_be_bytes(unsafe { *(bytes.as_ptr() as *const [u8; 8]) });
217
218        Ok(value)
219    }
220
221    /// ### Inexpensive Action
222    /// ( Just reads the type field of `LazyData` )
223    /// 
224    /// ---
225    /// Collects the `LazyData` as a boolean
226    /// 
227    /// Returns `LDBError::IncorrectType` if the type is not of boolean
228    pub fn collect_bool(self) -> Result<bool, LDBError> {
229        match self.lazy_type {
230            LazyType::True => Ok(true),
231            LazyType::False => Ok(false),
232            _ => Err(LDBError::IncorrectType(self.lazy_type, String::from("Boolean"))),
233        }
234    }
235
236    /// ### Inexpensive Action
237    /// ( Loads `LazyData` specified at path )
238    /// 
239    /// ---
240    /// Collects the `LazyData` as a path and converts that into another `LazyData`.
241    pub fn collect_link(self, database: LazyDB) -> Result<LazyData, LDBError> {
242        incorrect_type!(self.lazy_type, LazyType::Link);
243
244        // Loads string as a path
245        // Expensive and best to be avoided if possible
246        let bytes = self.wrapper.read_to_end()?;
247        
248        let string = if let Ok(x) = String::from_utf8(bytes.to_vec()) {
249            x
250        } else {
251            return Err(LDBError::InvalidUTF8String(bytes))
252        };
253
254        database.as_container()?.read_data(string)
255    }
256}