surrealml_core/storage/header/
mod.rs1pub mod engine;
3pub mod input_dims;
4pub mod keys;
5pub mod normalisers;
6pub mod origin;
7pub mod output;
8pub mod string_value;
9pub mod version;
10
11use engine::Engine;
12use input_dims::InputDims;
13use keys::KeyBindings;
14use normalisers::NormaliserMap;
15use normalisers::wrapper::NormaliserType;
16use origin::Origin;
17use output::Output;
18use string_value::StringValue;
19use version::Version;
20
21use crate::errors::error::{SurrealError, SurrealErrorStatus};
22use crate::safe_eject;
23
24#[derive(Debug, PartialEq)]
37pub struct Header {
38 pub keys: KeyBindings,
39 pub normalisers: NormaliserMap,
40 pub output: Output,
41 pub name: StringValue,
42 pub version: Version,
43 pub description: StringValue,
44 pub engine: Engine,
45 pub origin: Origin,
46 pub input_dims: InputDims,
47}
48
49impl Header {
50 pub fn fresh() -> Self {
55 Header {
56 keys: KeyBindings::fresh(),
57 normalisers: NormaliserMap::fresh(),
58 output: Output::fresh(),
59 name: StringValue::fresh(),
60 version: Version::fresh(),
61 description: StringValue::fresh(),
62 engine: Engine::fresh(),
63 origin: Origin::fresh(),
64 input_dims: InputDims::fresh(),
65 }
66 }
67
68 pub fn add_name(&mut self, model_name: String) {
73 self.name = StringValue::from_string(model_name);
74 }
75
76 pub fn add_version(&mut self, version: String) -> Result<(), SurrealError> {
81 self.version = Version::from_string(version)?;
82 Ok(())
83 }
84
85 pub fn add_description(&mut self, description: String) {
90 self.description = StringValue::from_string(description);
91 }
92
93 pub fn add_column(&mut self, column_name: String) {
100 self.keys.add_column(column_name);
101 }
102
103 pub fn add_normaliser(
109 &mut self,
110 column_name: String,
111 normaliser: NormaliserType,
112 ) -> Result<(), SurrealError> {
113 self.normalisers.add_normaliser(normaliser, column_name, &self.keys)?;
114 Ok(())
115 }
116
117 pub fn get_normaliser(
125 &self,
126 column_name: &String,
127 ) -> Result<Option<&NormaliserType>, SurrealError> {
128 self.normalisers.get_normaliser(column_name.to_string(), &self.keys)
129 }
130
131 pub fn add_output(&mut self, column_name: String, normaliser: Option<NormaliserType>) {
137 self.output.name = Some(column_name);
138 self.output.normaliser = normaliser;
139 }
140
141 pub fn add_engine(&mut self, engine: String) {
146 self.engine = Engine::from_string(engine);
147 }
148
149 pub fn add_author(&mut self, author: String) {
154 self.origin.add_author(author);
155 }
156
157 pub fn add_origin(&mut self, origin: String) -> Result<(), SurrealError> {
162 self.origin.add_origin(origin)
163 }
164
165 fn delimiter() -> &'static str {
167 "//=>"
168 }
169
170 pub fn from_bytes(data: Vec<u8>) -> Result<Self, SurrealError> {
178 let string_data = safe_eject!(String::from_utf8(data), SurrealErrorStatus::BadRequest);
179
180 let buffer = string_data.split(Self::delimiter()).collect::<Vec<&str>>();
181
182 let keys: KeyBindings = KeyBindings::from_string(buffer.get(1).unwrap_or(&"").to_string());
183 let normalisers =
184 NormaliserMap::from_string(buffer.get(2).unwrap_or(&"").to_string(), &keys)?;
185 let output = Output::from_string(buffer.get(3).unwrap_or(&"").to_string())?;
186 let name = StringValue::from_string(buffer.get(4).unwrap_or(&"").to_string());
187 let version = Version::from_string(buffer.get(5).unwrap_or(&"").to_string())?;
188 let description = StringValue::from_string(buffer.get(6).unwrap_or(&"").to_string());
189 let engine = Engine::from_string(buffer.get(7).unwrap_or(&"").to_string());
190 let origin = Origin::from_string(buffer.get(8).unwrap_or(&"").to_string())?;
191 let input_dims = InputDims::from_string(buffer.get(9).unwrap_or(&"").to_string())?;
192 Ok(Header {
193 keys,
194 normalisers,
195 output,
196 name,
197 version,
198 description,
199 engine,
200 origin,
201 input_dims,
202 })
203 }
204
205 pub fn to_bytes(&self) -> (i32, Vec<u8>) {
210 let buffer = vec![
211 "".to_string(),
212 self.keys.to_string(),
213 self.normalisers.to_string(),
214 self.output.to_string(),
215 self.name.to_string(),
216 self.version.to_string(),
217 self.description.to_string(),
218 self.engine.to_string(),
219 self.origin.to_string(),
220 self.input_dims.to_string(),
221 "".to_string(),
222 ];
223 let buffer = buffer.join(Self::delimiter()).into_bytes();
224 (buffer.len() as i32, buffer)
225 }
226}
227
228#[cfg(test)]
229mod tests {
230
231 use super::keys::tests::generate_string as generate_key_string;
232 use super::normalisers::clipping::Clipping;
233 use super::normalisers::linear_scaling::LinearScaling;
234 use super::normalisers::log_scale::LogScaling;
235 use super::normalisers::tests::generate_string as generate_normaliser_string;
236 use super::normalisers::z_score::ZScore;
237 use super::*;
238
239 pub fn generate_string() -> String {
240 let keys = generate_key_string();
241 let normalisers = generate_normaliser_string();
242 let output = "g=>linear_scaling(0.0,1.0)".to_string();
243 format!(
244 "{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}{}",
245 Header::delimiter(),
246 keys,
247 Header::delimiter(),
248 normalisers,
249 Header::delimiter(),
250 output,
251 Header::delimiter(),
252 "test model name",
253 Header::delimiter(),
254 "0.0.1",
255 Header::delimiter(),
256 "test description",
257 Header::delimiter(),
258 Engine::PyTorch,
259 Header::delimiter(),
260 Origin::from_string("author=>local".to_string()).unwrap(),
261 Header::delimiter(),
262 InputDims::from_string("1,2".to_string()).unwrap(),
263 Header::delimiter(),
264 )
265 }
266
267 pub fn generate_bytes() -> Vec<u8> {
268 generate_string().into_bytes()
269 }
270
271 #[test]
272 fn test_from_bytes() {
273 let header = Header::from_bytes(generate_bytes()).unwrap();
274
275 assert_eq!(header.keys.store.len(), 6);
276 assert_eq!(header.keys.reference.len(), 6);
277 assert_eq!(header.normalisers.store.len(), 4);
278
279 assert_eq!(header.keys.store[0], "a");
280 assert_eq!(header.keys.store[1], "b");
281 assert_eq!(header.keys.store[2], "c");
282 assert_eq!(header.keys.store[3], "d");
283 assert_eq!(header.keys.store[4], "e");
284 assert_eq!(header.keys.store[5], "f");
285 }
286
287 #[test]
288 fn test_empty_header() {
289 let string = "//=>//=>//=>//=>//=>//=>//=>//=>//=>".to_string();
290 let data = string.as_bytes();
291 let header = Header::from_bytes(data.to_vec()).unwrap();
292
293 assert_eq!(header, Header::fresh());
294
295 let string = "".to_string();
296 let data = string.as_bytes();
297 let header = Header::from_bytes(data.to_vec()).unwrap();
298
299 assert_eq!(header, Header::fresh());
300 }
301
302 #[test]
306 fn test_from_bytes_malformed_header_does_not_panic() {
307 let header = "//=>//=>//=>//=>m//=>1.2.3//=>desc//=>pytorch//=>author=>local//=>bad//=>";
308 let result = Header::from_bytes(header.as_bytes().to_vec());
309 assert!(result.is_err());
310 }
311
312 #[test]
313 fn test_to_bytes() {
314 let header = Header::from_bytes(generate_bytes()).unwrap();
315 let (bytes_num, bytes) = header.to_bytes();
316 let string = String::from_utf8(bytes).unwrap();
317
318 let expected_string = "//=>a=>b=>c=>d=>e=>f//=>a=>linear_scaling(0,1)//b=>clipping(0,1.5)//c=>log_scaling(10,0)//e=>z_score(0,1)//=>g=>linear_scaling(0,1)//=>test model name//=>0.0.1//=>test description//=>pytorch//=>author=>local//=>1,2//=>".to_string();
321
322 assert_eq!(string, expected_string);
323 assert_eq!(bytes_num, expected_string.len() as i32);
324
325 let empty_header = Header::fresh();
326 let (bytes_num, bytes) = empty_header.to_bytes();
327 let string = String::from_utf8(bytes).unwrap();
328 let expected_string = "//=>//=>//=>//=>//=>//=>//=>//=>//=>//=>".to_string();
329
330 assert_eq!(string, expected_string);
331 assert_eq!(bytes_num, expected_string.len() as i32);
332 }
333
334 #[test]
335 fn test_add_column() {
336 let mut header = Header::fresh();
337 header.add_column("a".to_string());
338 header.add_column("b".to_string());
339 header.add_column("c".to_string());
340 header.add_column("d".to_string());
341 header.add_column("e".to_string());
342 header.add_column("f".to_string());
343
344 assert_eq!(header.keys.store.len(), 6);
345 assert_eq!(header.keys.reference.len(), 6);
346
347 assert_eq!(header.keys.store[0], "a");
348 assert_eq!(header.keys.store[1], "b");
349 assert_eq!(header.keys.store[2], "c");
350 assert_eq!(header.keys.store[3], "d");
351 assert_eq!(header.keys.store[4], "e");
352 assert_eq!(header.keys.store[5], "f");
353 }
354
355 #[test]
356 fn test_add_normalizer() {
357 let mut header = Header::fresh();
358 header.add_column("a".to_string());
359 header.add_column("b".to_string());
360 header.add_column("c".to_string());
361 header.add_column("d".to_string());
362 header.add_column("e".to_string());
363 header.add_column("f".to_string());
364
365 let _ = header.add_normaliser(
366 "a".to_string(),
367 NormaliserType::LinearScaling(LinearScaling {
368 min: 0.0,
369 max: 1.0,
370 }),
371 );
372 let _ = header.add_normaliser(
373 "b".to_string(),
374 NormaliserType::Clipping(Clipping {
375 min: Some(0.0),
376 max: Some(1.5),
377 }),
378 );
379 let _ = header.add_normaliser(
380 "c".to_string(),
381 NormaliserType::LogScaling(LogScaling {
382 base: 10.0,
383 min: 0.0,
384 }),
385 );
386 let _ = header.add_normaliser(
387 "e".to_string(),
388 NormaliserType::ZScore(ZScore {
389 mean: 0.0,
390 std_dev: 1.0,
391 }),
392 );
393
394 assert_eq!(header.normalisers.store.len(), 4);
395 assert_eq!(
396 header.normalisers.store[0],
397 NormaliserType::LinearScaling(LinearScaling {
398 min: 0.0,
399 max: 1.0
400 })
401 );
402 assert_eq!(
403 header.normalisers.store[1],
404 NormaliserType::Clipping(Clipping {
405 min: Some(0.0),
406 max: Some(1.5)
407 })
408 );
409 assert_eq!(
410 header.normalisers.store[2],
411 NormaliserType::LogScaling(LogScaling {
412 base: 10.0,
413 min: 0.0
414 })
415 );
416 assert_eq!(
417 header.normalisers.store[3],
418 NormaliserType::ZScore(ZScore {
419 mean: 0.0,
420 std_dev: 1.0
421 })
422 );
423 }
424}