1use crate::convenience::split_results;
4use crate::error::DmapError;
5use crate::io::{self};
6use crate::io::{create_stream, slice_stream_lax, split_into_slices};
7use crate::types::{DmapField, DmapType, DmapVec, Fields};
8use indexmap::IndexMap;
9use itertools::izip;
10use rayon::iter::Either;
11use rayon::prelude::*;
12use std::fmt::Debug;
13use std::fs::File;
14use std::io::Read;
15use std::path::Path;
16
17pub trait Record<'a>:
22 Debug + Send + Sync + TryFrom<IndexMap<String, DmapField>, Error = DmapError>
23{
24 fn new(fields: &mut IndexMap<String, DmapField>) -> Result<Self, DmapError>
26 where
27 Self: Sized;
28
29 fn inner(self) -> IndexMap<String, DmapField>;
31
32 fn get(&self, key: &str) -> Option<&DmapField>;
34
35 fn keys(&self) -> Vec<&String>;
37
38 fn is_metadata_field(name: &str) -> bool;
40
41 fn read_nth_records(dmap_data: impl Read, indices: &[i32]) -> Result<Vec<Self>, DmapError>
45 where
46 Self: Sized,
47 Self: Send,
48 {
49 let mut slices = split_into_slices(dmap_data)?;
50 let num_recs = slices.len();
51 let mut records_read = vec![];
52 for idx in indices.iter() {
53 if *idx >= num_recs as i32 || *idx <= -1 * num_recs as i32 {
54 return Err(DmapError::InvalidIndex(*idx));
55 }
56 let i = {
57 if *idx < 0 {
58 num_recs - idx.abs() as usize
59 } else {
60 *idx as usize
61 }
62 };
63 records_read.push(slices[i].parse_record::<Self>().map_err(|e| {
64 DmapError::InvalidRecord(format!("Record {idx}: {}", e.to_string()))
65 })?);
66 }
67 Ok(records_read)
68 }
69
70 fn read_nth_records_lax(
75 mut dmap_data: impl Read,
76 indices: &[i32],
77 ) -> Result<(Vec<Self>, Option<usize>), DmapError>
78 where
79 Self: Sized,
80 Self: Send,
81 {
82 let mut buffer: Vec<u8> = vec![];
83 let mut dmap_records: Vec<Self> = vec![];
84
85 create_stream(&mut dmap_data)?.read_to_end(&mut buffer)?;
86 let (mut slices, rec_starts, mut bad_byte) = slice_stream_lax(buffer);
87
88 let num_recs = slices.len();
89 for idx in indices.iter() {
90 if *idx >= num_recs as i32 || *idx <= -1 * num_recs as i32 {
91 return Err(DmapError::InvalidIndex(*idx));
92 }
93 let i = {
94 if *idx < 0 {
95 num_recs - idx.abs() as usize
96 } else {
97 *idx as usize
98 }
99 };
100 let parse_result = slices[i].parse_record::<Self>();
101 if let Ok(x) = parse_result {
102 dmap_records.push(x);
103 } else {
104 bad_byte = Some(rec_starts[i]);
105 break;
106 }
107 }
108
109 Ok((dmap_records, bad_byte))
110 }
111
112 fn read_records(dmap_data: impl Read) -> Result<Vec<Self>, DmapError>
116 where
117 Self: Sized,
118 Self: Send,
119 {
120 let mut slices = split_into_slices(dmap_data)?;
121 let mut dmap_results: Vec<Result<Self, DmapError>> = vec![];
122 dmap_results.par_extend(
123 slices
124 .par_iter_mut()
125 .map(|parser| parser.parse_record::<Self>()),
126 );
127
128 let (dmap_records, dmap_errors, bad_recs) = split_results(dmap_results);
129 if !dmap_errors.is_empty() {
130 return Err(DmapError::BadRecords(bad_recs, dmap_errors[0].to_string()));
131 }
132 Ok(dmap_records)
133 }
134
135 fn read_metadata(dmap_data: impl Read) -> Result<Vec<IndexMap<String, DmapField>>, DmapError>
139 where
140 Self: Sized,
141 Self: Send,
142 {
143 let mut slices = split_into_slices(dmap_data)?;
144 let mut dmap_results: Vec<Result<IndexMap<String, DmapField>, DmapError>> = vec![];
145 dmap_results.par_extend(
146 slices
147 .par_iter_mut()
148 .map(|parser| parser.parse_metadata::<Self>()),
149 );
150
151 let (dmap_records, dmap_errors, bad_recs) = split_results(dmap_results);
152 if !dmap_errors.is_empty() {
153 return Err(DmapError::BadRecords(bad_recs, dmap_errors[0].to_string()));
154 }
155
156 Ok(dmap_records)
157 }
158
159 fn read_metadata_by_indices(
163 dmap_data: impl Read,
164 indices: &[i32],
165 ) -> Result<Vec<IndexMap<String, DmapField>>, DmapError>
166 where
167 Self: Sized,
168 Self: Send,
169 {
170 let mut slices = split_into_slices(dmap_data)?;
171 let mut dmap_results: Vec<IndexMap<String, DmapField>> = vec![];
172
173 let num_recs = slices.len();
174 for idx in indices.iter() {
175 if *idx >= num_recs as i32 || *idx <= -1 * num_recs as i32 {
176 return Err(DmapError::InvalidIndex(*idx));
177 }
178 let i = {
179 if *idx < 0 {
180 num_recs - idx.abs() as usize
181 } else {
182 *idx as usize
183 }
184 };
185 dmap_results.push(slices[i].parse_metadata::<Self>().map_err(|e| {
186 DmapError::InvalidRecord(format!("Record {idx}: {}", e.to_string()))
187 })?);
188 }
189 Ok(dmap_results)
190 }
191
192 fn read_records_lax(mut dmap_data: impl Read) -> Result<(Vec<Self>, Option<usize>), DmapError>
197 where
198 Self: Sized,
199 Self: Send,
200 {
201 let mut buffer: Vec<u8> = vec![];
202 let mut dmap_records: Vec<Self> = vec![];
203
204 create_stream(&mut dmap_data)?.read_to_end(&mut buffer)?;
205 let (mut slices, rec_starts, mut bad_byte) = slice_stream_lax(buffer);
206
207 let mut dmap_results: Vec<Result<Self, DmapError>> = vec![];
208 dmap_results.par_extend(
209 slices
210 .par_iter_mut()
211 .map(|parser| parser.parse_record::<Self>()),
212 );
213
214 for (i, rec) in dmap_results.into_iter().enumerate() {
215 if let Ok(x) = rec {
216 dmap_records.push(x);
217 } else {
218 bad_byte = Some(rec_starts[i]);
219 break;
220 }
221 }
222 Ok((dmap_records, bad_byte))
223 }
224
225 fn read_file<P: AsRef<Path>>(infile: P) -> Result<Vec<Self>, DmapError>
227 where
228 Self: Sized,
229 Self: Send,
230 {
231 let file = File::open(infile)?;
232 Self::read_records(file)
233 }
234
235 fn read_file_lax<P: AsRef<Path>>(infile: P) -> Result<(Vec<Self>, Option<usize>), DmapError>
240 where
241 Self: Sized,
242 Self: Send,
243 {
244 let file = File::open(infile)?;
245 Self::read_records_lax(file)
246 }
247
248 fn read_file_by_indices<P: AsRef<Path>>(
250 infile: P,
251 indices: &[i32],
252 ) -> Result<Vec<Self>, DmapError>
253 where
254 Self: Sized,
255 Self: Send,
256 {
257 let file = File::open(infile)?;
258 Self::read_nth_records(file, indices)
259 }
260
261 fn read_file_by_indices_lax<P: AsRef<Path>>(
266 infile: P,
267 indices: &[i32],
268 ) -> Result<(Vec<Self>, Option<usize>), DmapError>
269 where
270 Self: Sized,
271 Self: Send,
272 {
273 let file = File::open(infile)?;
274 Self::read_nth_records_lax(file, indices)
275 }
276
277 fn read_file_metadata<P: AsRef<Path>>(
279 infile: P,
280 ) -> Result<Vec<IndexMap<String, DmapField>>, DmapError>
281 where
282 Self: Sized,
283 Self: Send,
284 {
285 let file = File::open(infile)?;
286 Self::read_metadata(file)
287 }
288
289 fn read_file_metadata_by_indices<P: AsRef<Path>>(
291 infile: P,
292 indices: &[i32],
293 ) -> Result<Vec<IndexMap<String, DmapField>>, DmapError>
294 where
295 Self: Sized,
296 Self: Send,
297 {
298 let file = File::open(infile)?;
299 Self::read_metadata_by_indices(file, indices)
300 }
301
302 fn check_fields(
309 field_dict: &mut IndexMap<String, DmapField>,
310 fields_for_type: &Fields,
311 ) -> Result<(), DmapError> {
312 let unsupported_keys: Vec<&String> = field_dict
313 .keys()
314 .filter(|&k| !fields_for_type.all_fields.contains(&&**k))
315 .collect();
316 if !unsupported_keys.is_empty() {
317 Err(DmapError::InvalidRecord(format!(
318 "Unsupported fields {:?}, fields supported are {:?}",
319 unsupported_keys, fields_for_type.all_fields
320 )))?
321 }
322
323 for (field, expected_type) in fields_for_type.scalars_required.iter() {
324 match field_dict.get(&field.to_string()) {
325 Some(DmapField::Scalar(x)) if &x.get_type() == expected_type => {}
326 Some(DmapField::Scalar(x)) => Err(DmapError::InvalidRecord(format!(
327 "Field {} has incorrect type {}, expected {}",
328 field,
329 x.get_type(),
330 expected_type
331 )))?,
332 Some(_) => Err(DmapError::InvalidRecord(format!(
333 "Field {} is a vector, expected scalar",
334 field
335 )))?,
336 None => Err(DmapError::InvalidRecord(format!(
337 "Field {field:?} ({:?}) missing: fields {:?}",
338 &field.to_string(),
339 field_dict.keys()
340 )))?,
341 }
342 }
343 for (field, expected_type) in fields_for_type.scalars_optional.iter() {
344 match field_dict.get(&field.to_string()) {
345 Some(DmapField::Scalar(x)) if &x.get_type() == expected_type => {}
346 Some(DmapField::Scalar(x)) => Err(DmapError::InvalidRecord(format!(
347 "Field {} has incorrect type {}, expected {}",
348 field,
349 x.get_type(),
350 expected_type
351 )))?,
352 Some(_) => Err(DmapError::InvalidRecord(format!(
353 "Field {} is a vector, expected scalar",
354 field
355 )))?,
356 None => {}
357 }
358 }
359 for (field, expected_type) in fields_for_type.vectors_required.iter() {
360 match field_dict.get(&field.to_string()) {
361 Some(DmapField::Scalar(_)) => Err(DmapError::InvalidRecord(format!(
362 "Field {} is a scalar, expected vector",
363 field
364 )))?,
365 Some(DmapField::Vector(x)) if &x.get_type() != expected_type => {
366 Err(DmapError::InvalidRecord(format!(
367 "Field {field} has incorrect type {:?}, expected {expected_type:?}",
368 x.get_type()
369 )))?
370 }
371 Some(&DmapField::Vector(_)) => {}
372 None => Err(DmapError::InvalidRecord(format!("Field {field} missing")))?,
373 }
374 }
375 for (field, expected_type) in fields_for_type.vectors_optional.iter() {
376 match field_dict.get(&field.to_string()) {
377 Some(&DmapField::Scalar(_)) => Err(DmapError::InvalidRecord(format!(
378 "Field {} is a scalar, expected vector",
379 field
380 )))?,
381 Some(DmapField::Vector(x)) if &x.get_type() != expected_type => {
382 Err(DmapError::InvalidRecord(format!(
383 "Field {field} has incorrect type {}, expected {expected_type}",
384 x.get_type()
385 )))?
386 }
387 _ => {}
388 }
389 }
390 for vec_group in fields_for_type.vector_dim_groups.iter() {
392 let vecs: Vec<(&str, &DmapVec)> = vec_group
393 .iter()
394 .filter_map(|&name| match field_dict.get(&name.to_string()) {
395 Some(DmapField::Vector(ref x)) => Some((name, x)),
396 Some(_) => None,
397 None => None,
398 })
399 .collect();
400 if vecs.len() > 1 {
401 let mut vec_iter = vecs.iter();
402 let first = vec_iter.next().expect("Iterator broken");
403 if !vec_iter.all(|(_, v)| v.shape() == first.1.shape()) {
404 let error_vec: Vec<(&str, &[usize])> =
405 vecs.iter().map(|(k, v)| (*k, v.shape())).collect();
406 Err(DmapError::InvalidRecord(format!(
407 "Vector fields have inconsistent dimensions: {:?}",
408 error_vec
409 )))?
410 }
411 }
412 }
413 Ok(())
414 }
415
416 fn coerce(
418 fields_dict: &mut IndexMap<String, DmapField>,
419 fields_for_type: &Fields,
420 ) -> Result<Self, DmapError> {
421 let unsupported_keys: Vec<&String> = fields_dict
422 .keys()
423 .filter(|&k| !fields_for_type.all_fields.contains(&&**k))
424 .collect();
425 if !unsupported_keys.is_empty() {
426 Err(DmapError::InvalidRecord(format!(
427 "Unsupported fields {:?}, fields supported are {:?}",
428 unsupported_keys, fields_for_type.all_fields
429 )))?
430 }
431
432 for (field, expected_type) in fields_for_type.scalars_required.iter() {
433 match fields_dict.get(&field.to_string()) {
434 Some(DmapField::Scalar(x)) if &x.get_type() != expected_type => {
435 fields_dict.insert(
436 field.to_string(),
437 DmapField::Scalar(x.cast_as(expected_type)?),
438 );
439 }
440 Some(DmapField::Scalar(_)) => {}
441 Some(_) => Err(DmapError::InvalidRecord(format!(
442 "Field {} is a vector, expected scalar",
443 field
444 )))?,
445 None => Err(DmapError::InvalidRecord(format!(
446 "Field {field:?} ({:?}) missing: fields {:?}",
447 &field.to_string(),
448 fields_dict.keys()
449 )))?,
450 }
451 }
452 for (field, expected_type) in fields_for_type.scalars_optional.iter() {
453 match fields_dict.get(&field.to_string()) {
454 Some(DmapField::Scalar(x)) if &x.get_type() == expected_type => {}
455 Some(DmapField::Scalar(x)) => {
456 fields_dict.insert(
457 field.to_string(),
458 DmapField::Scalar(x.cast_as(expected_type)?),
459 );
460 }
461 Some(_) => Err(DmapError::InvalidRecord(format!(
462 "Field {} is a vector, expected scalar",
463 field
464 )))?,
465 None => {}
466 }
467 }
468 for (field, expected_type) in fields_for_type.vectors_required.iter() {
469 match fields_dict.get(&field.to_string()) {
470 Some(DmapField::Scalar(_)) => Err(DmapError::InvalidRecord(format!(
471 "Field {} is a scalar, expected vector",
472 field
473 )))?,
474 Some(DmapField::Vector(x)) if &x.get_type() != expected_type => {
475 Err(DmapError::InvalidRecord(format!(
476 "Field {field} has incorrect type {:?}, expected {expected_type:?}",
477 x.get_type()
478 )))?
479 }
480 Some(DmapField::Vector(_)) => {}
481 None => Err(DmapError::InvalidRecord(format!("Field {field} missing")))?,
482 }
483 }
484 for (field, expected_type) in fields_for_type.vectors_optional.iter() {
485 match fields_dict.get(&field.to_string()) {
486 Some(&DmapField::Scalar(_)) => Err(DmapError::InvalidRecord(format!(
487 "Field {} is a scalar, expected vector",
488 field
489 )))?,
490 Some(DmapField::Vector(x)) if &x.get_type() != expected_type => {
491 Err(DmapError::InvalidRecord(format!(
492 "Field {field} has incorrect type {}, expected {expected_type}",
493 x.get_type()
494 )))?
495 }
496 _ => {}
497 }
498 }
499
500 Self::new(fields_dict)
501 }
502
503 fn to_bytes(&self) -> Result<Vec<u8>, DmapError>;
505
506 fn data_to_bytes(
514 data: &IndexMap<String, DmapField>,
515 fields_for_type: &Fields,
516 ) -> Result<(i32, i32, Vec<u8>), DmapError> {
517 let mut data_bytes: Vec<u8> = vec![];
518 let mut num_scalars: i32 = 0;
519 let mut num_vectors: i32 = 0;
520
521 for (field, _) in fields_for_type.scalars_required.iter() {
523 match data.get(&field.to_string()) {
524 Some(x @ DmapField::Scalar(_)) => {
525 data_bytes.extend(field.as_bytes());
526 data_bytes.extend([0]); data_bytes.append(&mut x.as_bytes());
528 num_scalars += 1;
529 }
530 Some(_) => Err(DmapError::InvalidScalar(format!(
531 "Field {field} is a vector, expected scalar"
532 )))?,
533 None => Err(DmapError::InvalidRecord(format!(
534 "Field {field} missing from record"
535 )))?,
536 }
537 }
538 for (field, _) in fields_for_type.scalars_optional.iter() {
539 if let Some(x) = data.get(&field.to_string()) {
540 match x {
541 DmapField::Scalar(_) => {
542 data_bytes.extend(field.as_bytes());
543 data_bytes.extend([0]); data_bytes.append(&mut x.as_bytes());
545 num_scalars += 1;
546 }
547 DmapField::Vector(_) => Err(DmapError::InvalidScalar(format!(
548 "Field {field} is a vector, expected scalar"
549 )))?,
550 }
551 }
552 }
553 for (field, _) in fields_for_type.vectors_required.iter() {
554 match data.get(&field.to_string()) {
555 Some(x @ DmapField::Vector(_)) => {
556 data_bytes.extend(field.as_bytes());
557 data_bytes.extend([0]); data_bytes.append(&mut x.as_bytes());
559 num_vectors += 1;
560 }
561 Some(_) => Err(DmapError::InvalidVector(format!(
562 "Field {field} is a scalar, expected vector"
563 )))?,
564 None => Err(DmapError::InvalidRecord(format!(
565 "Field {field} missing from record"
566 )))?,
567 }
568 }
569 for (field, _) in fields_for_type.vectors_optional.iter() {
570 if let Some(x) = data.get(&field.to_string()) {
571 match x {
572 DmapField::Vector(_) => {
573 data_bytes.extend(field.as_bytes());
574 data_bytes.extend([0]); data_bytes.append(&mut x.as_bytes());
576 num_vectors += 1;
577 }
578 DmapField::Scalar(_) => Err(DmapError::InvalidVector(format!(
579 "Field {field} is a scalar, expected vector"
580 )))?,
581 }
582 }
583 }
584
585 Ok((num_scalars, num_vectors, data_bytes))
586 }
587
588 fn inspect_bytes(
595 &self,
596 fields_for_type: &Fields,
597 ) -> Result<Vec<(String, usize, Vec<u8>)>, DmapError> {
598 let mut data_bytes: Vec<Vec<u8>> = vec![];
599 let mut indices: Vec<usize> = vec![16]; let mut fields: Vec<String> = vec![];
601
602 let (mut num_scalars, mut num_vectors) = (0, 0);
603
604 for (field, _) in fields_for_type.scalars_required.iter() {
605 fields.push(field.to_string());
606 match self.get(field) {
607 Some(x @ DmapField::Scalar(_)) => {
608 let mut bytes = vec![];
609 bytes.extend(field.as_bytes());
610 bytes.extend([0]); bytes.append(&mut x.as_bytes());
612 indices.push(indices[indices.len() - 1] + bytes.len());
613 data_bytes.push(bytes);
614 num_scalars += 1;
615 }
616 Some(_) => Err(DmapError::InvalidScalar(format!(
617 "Field {field} is a vector, expected scalar"
618 )))?,
619 None => Err(DmapError::InvalidRecord(format!(
620 "Field {field} missing from record"
621 )))?,
622 }
623 }
624 for (field, _) in fields_for_type.scalars_optional.iter() {
625 fields.push(field.to_string());
626 if let Some(x) = self.get(field) {
627 match x {
628 DmapField::Scalar(_) => {
629 let mut bytes = vec![];
630 bytes.extend(field.as_bytes());
631 bytes.extend([0]); bytes.append(&mut x.as_bytes());
633 indices.push(indices[indices.len() - 1] + bytes.len());
634 data_bytes.push(bytes);
635 num_scalars += 1;
636 }
637 DmapField::Vector(_) => Err(DmapError::InvalidScalar(format!(
638 "Field {field} is a vector, expected scalar"
639 )))?,
640 }
641 }
642 }
643 for (field, _) in fields_for_type.vectors_required.iter() {
644 fields.push(field.to_string());
645 match self.get(field) {
646 Some(x @ DmapField::Vector(_)) => {
647 let mut bytes = vec![];
648 bytes.extend(field.as_bytes());
649 bytes.extend([0]); bytes.append(&mut x.as_bytes());
651 indices.push(indices[indices.len() - 1] + bytes.len());
652 data_bytes.push(bytes);
653 num_vectors += 1;
654 }
655 Some(_) => Err(DmapError::InvalidVector(format!(
656 "Field {field} is a scalar, expected vector"
657 )))?,
658 None => Err(DmapError::InvalidRecord(format!(
659 "Field {field} missing from record"
660 )))?,
661 }
662 }
663 for (field, _) in fields_for_type.vectors_optional.iter() {
664 fields.push(field.to_string());
665 if let Some(x) = self.get(field) {
666 match x {
667 DmapField::Vector(_) => {
668 let mut bytes = vec![];
669 bytes.extend(field.as_bytes());
670 bytes.extend([0]); bytes.append(&mut x.as_bytes());
672 indices.push(indices[indices.len() - 1] + data_bytes.len());
673 data_bytes.push(bytes);
674 num_vectors += 1;
675 }
676 DmapField::Scalar(_) => Err(DmapError::InvalidVector(format!(
677 "Field {field} is a scalar, expected vector"
678 )))?,
679 }
680 }
681 }
682
683 let num_bytes: usize = data_bytes.iter().map(|x| x.len()).sum();
685 let mut bytes: Vec<u8> = vec![];
686 bytes.extend((65537_i32).as_bytes()); bytes.extend((num_bytes as i32 + 16).as_bytes()); bytes.extend(num_scalars.as_bytes());
689 bytes.extend(num_vectors.as_bytes());
690
691 let mut field_info: Vec<(String, usize, Vec<u8>)> = vec![("header".to_string(), 0, bytes)];
693 for (f, (s, b)) in izip!(
694 fields.into_iter(),
695 izip!(indices[..indices.len() - 1].iter(), data_bytes.into_iter())
696 ) {
697 field_info.push((f, *s, b));
698 }
699
700 Ok(field_info)
701 }
702
703 fn par_to_bytes(recs: &[Self]) -> Result<Vec<u8>, DmapError> {
707 let mut bytes: Vec<u8> = vec![];
708 let (errors, rec_bytes): (Vec<_>, Vec<_>) =
709 recs.par_iter()
710 .enumerate()
711 .partition_map(|(i, rec)| match rec.to_bytes() {
712 Err(e) => Either::Left((i, e)),
713 Ok(y) => Either::Right(y),
714 });
715 if !errors.is_empty() {
716 Err(DmapError::InvalidRecord(format!(
717 "Corrupted records: {errors:?}"
718 )))?
719 }
720 bytes.par_extend(rec_bytes.into_par_iter().flatten());
721 Ok(bytes)
722 }
723
724 fn try_into_bytes(recs: Vec<IndexMap<String, DmapField>>) -> Result<Vec<u8>, DmapError> {
726 let mut bytes: Vec<u8> = vec![];
727 let (errors, rec_bytes): (Vec<_>, Vec<_>) =
728 recs.into_par_iter()
729 .enumerate()
730 .partition_map(|(i, rec)| match Self::try_from(rec) {
731 Err(e) => Either::Left((i, e)),
732 Ok(x) => match x.to_bytes() {
733 Err(e) => Either::Left((i, e)),
734 Ok(y) => Either::Right(y),
735 },
736 });
737 if !errors.is_empty() {
738 Err(DmapError::BadRecords(
739 errors.iter().map(|(i, _)| *i).collect(),
740 errors[0].1.to_string(),
741 ))?
742 }
743 bytes.par_extend(rec_bytes.into_par_iter().flatten());
744 Ok(bytes)
745 }
746
747 fn write_to_file<P: AsRef<Path>>(
753 recs: &Vec<Self>,
754 outfile: P,
755 bz2: bool,
756 ) -> Result<(), DmapError> {
757 let bytes: Vec<u8> = Self::par_to_bytes(recs)?;
758 io::bytes_to_file(bytes, outfile, bz2)?;
759 Ok(())
760 }
761
762 fn try_write_to_file<P: AsRef<Path>>(
774 recs: Vec<IndexMap<String, DmapField>>,
775 outfile: P,
776 bz2: bool,
777 ) -> Result<(), DmapError> {
778 let bytes = Self::try_into_bytes(recs)?;
779 io::bytes_to_file(bytes, outfile, bz2)?;
780 Ok(())
781 }
782}
783
784macro_rules! create_record_type {
785 ($format:ident, $fields:ident) => {
786 paste::paste! {
787 use crate::types::{DmapType, DmapField};
788 use crate::error::DmapError;
789 use indexmap::IndexMap;
790 use crate::record::Record;
791
792 #[doc = "Struct containing the checked fields of a single `" $format:upper "` record." ]
793 #[derive(Debug, PartialEq, Clone)]
794 pub struct [< $format:camel Record >] {
795 pub data: IndexMap<String, DmapField>,
796 }
797
798 impl Record<'_> for [< $format:camel Record>] {
799 fn inner(self) -> IndexMap<String, DmapField> {
800 self.data
801 }
802 fn get(&self, key: &str) -> Option<&DmapField> {
803 self.data.get(key)
804 }
805 fn keys(&self) -> Vec<&String> {
806 self.data.keys().collect()
807 }
808 fn new(fields: &mut IndexMap<String, DmapField>) -> Result<[< $format:camel Record>], DmapError> {
809 match Self::check_fields(fields, &$fields) {
810 Ok(_) => {}
811 Err(e) => Err(e)?,
812 }
813
814 Ok([< $format:camel Record >] {
815 data: fields.to_owned(),
816 })
817 }
818 fn to_bytes(&self) -> Result<Vec<u8>, DmapError> {
819 let (num_scalars, num_vectors, mut data_bytes) =
820 Self::data_to_bytes(&self.data, &$fields)?;
821
822 let mut bytes: Vec<u8> = vec![];
823 bytes.extend((65537_i32).as_bytes()); bytes.extend((data_bytes.len() as i32 + 16).as_bytes()); bytes.extend(num_scalars.as_bytes());
826 bytes.extend(num_vectors.as_bytes());
827 bytes.append(&mut data_bytes); Ok(bytes)
829 }
830 fn is_metadata_field(name: &str) -> bool {
831 !$fields.data_fields.iter().any(|e| e == &name)
832 }
833 }
834
835 impl TryFrom<&mut IndexMap<String, DmapField>> for [< $format:camel Record >] {
836 type Error = DmapError;
837
838 fn try_from(value: &mut IndexMap<String, DmapField>) -> Result<Self, Self::Error> {
839 Self::coerce(value, &$fields)
840 }
841 }
842
843 impl TryFrom<IndexMap<String, DmapField>> for [< $format:camel Record >] {
844 type Error = DmapError;
845
846 fn try_from(mut value: IndexMap<String, DmapField>) -> Result<Self, Self::Error> {
847 Self::coerce(&mut value, &$fields)
848 }
849 }
850
851 #[cfg(test)]
852 mod tests {
853 use super::*;
854 use std::path::PathBuf;
855
856 #[test]
859 fn test_missing_optional_fields() -> Result<(), DmapError> {
860 let filename: PathBuf = PathBuf::from(format!("tests/test_files/test.{}", stringify!($format)));
861 let data = [< $format:camel Record >]::read_file_by_indices(&filename, &[0]).expect("Unable to sniff file");
862 let recs = data[0].clone().inner();
863
864 for field in $fields.scalars_optional.iter().chain($fields.vectors_optional.iter()) {
865 let mut cloned_rec = recs.clone();
866 let _ = cloned_rec.shift_remove(field.0);
867 let _ = [< $format:camel Record >]::try_from(&mut cloned_rec)?;
868 }
869 Ok(())
870 }
871
872 #[test]
875 fn test_missing_required_fields() -> Result<(), DmapError> {
876 let filename: PathBuf = PathBuf::from(format!("tests/test_files/test.{}", stringify!($format)));
877 let data = [< $format:camel Record >]::read_file_by_indices(&filename, &[0]).expect("Unable to sniff file");
878 let recs = data[0].clone().inner();
879
880 for field in $fields.scalars_required.iter().chain($fields.vectors_required.iter()) {
881 let mut cloned_rec = recs.clone();
882 let _ = cloned_rec.shift_remove(field.0);
883 let res = [< $format:camel Record >]::try_from(&mut cloned_rec);
884 assert!(res.is_err());
885 }
886 Ok(())
887 }
888 }
889 }
890 }
891}
892
893pub(crate) use create_record_type;