1use std::collections::HashMap;
2
3use crate::{
4 numbers::Integer,
5 value::{GetValue, ShapedArray, Value, ValueArray},
6};
7
8#[derive(Clone, Debug, Default)]
21pub struct DataFile<Int> {
22 pub(crate) values: HashMap<String, Value<Int>>,
23 pub(crate) arrays_1d: HashMap<String, ValueArray<Int, 1>>,
24 pub(crate) arrays_2d: HashMap<String, ValueArray<Int, 2>>,
25}
26
27impl<Int: Integer> DataFile<Int> {
28 pub fn get<T>(&self, key: &str) -> Option<&T>
34 where
35 Value<Int>: GetValue<T>,
36 {
37 self.values.get(key).and_then(|value| value.try_get())
38 }
39
40 pub fn array_1d<T>(&self, key: &str, length: usize) -> Option<&ShapedArray<T, 1>>
42 where
43 ValueArray<Int, 1>: GetValue<ShapedArray<T, 1>>,
44 {
45 self.arrays_1d
46 .get(key)
47 .and_then(|array| array.try_get())
48 .filter(move |&array| array.shape == [length])
49 }
50
51 pub fn array_2d<T>(&self, key: &str, shape: [usize; 2]) -> Option<&ShapedArray<T, 2>>
55 where
56 ValueArray<Int, 2>: GetValue<ShapedArray<T, 2>>,
57 {
58 self.arrays_2d
59 .get(key)
60 .and_then(|array| array.try_get())
61 .filter(move |&array| array.shape == shape)
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use proptest::{proptest, strategy::Strategy};
68
69 use super::*;
70
71 fn ident() -> impl Strategy<Value = String> {
72 proptest::string::string_regex("[A-Za-z][A-Za-z0-9_]*").expect("valid regex")
73 }
74
75 fn int_map() -> impl Strategy<Value = HashMap<String, i32>> {
76 proptest::collection::hash_map(ident(), proptest::prelude::any::<i32>(), 1..5)
77 }
78
79 proptest! {
80 #[test]
81 fn integers_are_found(values in int_map()) {
82 let data_file = DataFile {
83 values: values.iter().map(|(k, v)| (k.clone(), Value::Int(*v))).collect(),
84 ..Default::default()
85 };
86
87 for (key, value) in values.iter() {
88 assert_eq!(Some(value), data_file.get::<i32>(key.as_str()));
89 }
90 }
91 }
92
93 proptest! {
94 #[test]
95 fn nonexistent_integer_values_return_none(label in ident()) {
96 let data_file: DataFile<i32> = DataFile { values: [].into(), ..Default::default() };
97
98 assert_eq!(None, data_file.get::<i32>(&label));
99 }
100 }
101}