1use std::collections::HashMap;
7
8use ndarray::ArrayViewD;
9
10use crate::block::access::BlockAccess;
11use crate::frame::Frame;
12use crate::frame_view::FrameView;
13use crate::region::simbox::SimBox;
14use crate::types::{F, I, U};
15
16pub trait FrameAccess {
21 fn get_float(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, F>>;
23 fn get_int(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, I>>;
25 fn get_bool(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, bool>>;
27 fn get_uint(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, U>>;
29 fn get_u8(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, u8>>;
31 fn get_string(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, String>>;
33 fn simbox_ref(&self) -> Option<&SimBox>;
35 fn meta_ref(&self) -> &HashMap<String, String>;
37 fn block_keys(&self) -> Vec<&str>;
39 fn contains_block(&self, key: &str) -> bool;
41 fn block_count(&self) -> usize;
43 fn is_empty(&self) -> bool;
45 fn visit_block<R>(&self, key: &str, f: impl FnOnce(&dyn BlockAccess) -> R) -> Option<R>;
48}
49
50impl FrameAccess for Frame {
51 fn get_float(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, F>> {
52 self.get(block_key)
53 .and_then(|b| b.get_float(col_key))
54 .map(|a| a.view())
55 }
56
57 fn get_int(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, I>> {
58 self.get(block_key)
59 .and_then(|b| b.get_int(col_key))
60 .map(|a| a.view())
61 }
62
63 fn get_bool(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, bool>> {
64 self.get(block_key)
65 .and_then(|b| b.get_bool(col_key))
66 .map(|a| a.view())
67 }
68
69 fn get_uint(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, U>> {
70 self.get(block_key)
71 .and_then(|b| b.get_uint(col_key))
72 .map(|a| a.view())
73 }
74
75 fn get_u8(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, u8>> {
76 self.get(block_key)
77 .and_then(|b| b.get_u8(col_key))
78 .map(|a| a.view())
79 }
80
81 fn get_string(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, String>> {
82 self.get(block_key)
83 .and_then(|b| b.get_string(col_key))
84 .map(|a| a.view())
85 }
86
87 fn simbox_ref(&self) -> Option<&SimBox> {
88 self.simbox.as_ref()
89 }
90
91 fn meta_ref(&self) -> &HashMap<String, String> {
92 &self.meta
93 }
94
95 fn block_keys(&self) -> Vec<&str> {
96 self.keys().collect()
97 }
98
99 fn contains_block(&self, key: &str) -> bool {
100 self.contains_key(key)
101 }
102
103 fn block_count(&self) -> usize {
104 self.len()
105 }
106
107 fn is_empty(&self) -> bool {
108 Frame::is_empty(self)
109 }
110
111 fn visit_block<R>(&self, key: &str, f: impl FnOnce(&dyn BlockAccess) -> R) -> Option<R> {
112 self.get(key).map(|block| f(block))
113 }
114}
115
116impl FrameAccess for FrameView<'_> {
117 fn get_float(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, F>> {
118 self.get(block_key).and_then(|b| b.get_float(col_key))
119 }
120
121 fn get_int(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, I>> {
122 self.get(block_key).and_then(|b| b.get_int(col_key))
123 }
124
125 fn get_bool(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, bool>> {
126 self.get(block_key).and_then(|b| b.get_bool(col_key))
127 }
128
129 fn get_uint(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, U>> {
130 self.get(block_key).and_then(|b| b.get_uint(col_key))
131 }
132
133 fn get_u8(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, u8>> {
134 self.get(block_key).and_then(|b| b.get_u8(col_key))
135 }
136
137 fn get_string(&self, block_key: &str, col_key: &str) -> Option<ArrayViewD<'_, String>> {
138 self.get(block_key).and_then(|b| b.get_string(col_key))
139 }
140
141 fn simbox_ref(&self) -> Option<&SimBox> {
142 self.simbox
143 }
144
145 fn meta_ref(&self) -> &HashMap<String, String> {
146 self.meta
147 }
148
149 fn block_keys(&self) -> Vec<&str> {
150 self.keys().copied().collect()
151 }
152
153 fn contains_block(&self, key: &str) -> bool {
154 self.contains_key(key)
155 }
156
157 fn block_count(&self) -> usize {
158 self.len()
159 }
160
161 fn is_empty(&self) -> bool {
162 FrameView::is_empty(self)
163 }
164
165 fn visit_block<R>(&self, key: &str, f: impl FnOnce(&dyn BlockAccess) -> R) -> Option<R> {
166 self.get(key).map(|block_view| f(block_view))
167 }
168}
169
170#[cfg(test)]
171mod tests {
172 use super::*;
173 use crate::block::Block;
174 use crate::types::{F, I};
175 use ndarray::Array1;
176
177 fn make_frame() -> Frame {
178 let mut frame = Frame::new();
179 let mut atoms = Block::new();
180 atoms
181 .insert("x", Array1::from_vec(vec![1.0 as F, 2.0, 3.0]).into_dyn())
182 .unwrap();
183 atoms
184 .insert("id", Array1::from_vec(vec![10 as I, 20, 30]).into_dyn())
185 .unwrap();
186 frame.insert("atoms", atoms);
187 frame.meta.insert("title".into(), "Test".into());
188 frame
189 }
190
191 #[test]
192 fn test_frame_access_on_frame() {
193 let frame = make_frame();
194 assert!(FrameAccess::get_float(&frame, "atoms", "x").is_some());
195 assert!(FrameAccess::get_int(&frame, "atoms", "id").is_some());
196 assert!(FrameAccess::get_float(&frame, "atoms", "missing").is_none());
197 assert!(FrameAccess::get_float(&frame, "missing", "x").is_none());
198 assert_eq!(FrameAccess::block_count(&frame), 1);
199 assert!(FrameAccess::contains_block(&frame, "atoms"));
200 assert!(!FrameAccess::is_empty(&frame));
201 assert_eq!(FrameAccess::meta_ref(&frame).get("title").unwrap(), "Test");
202 assert!(FrameAccess::simbox_ref(&frame).is_none());
203 }
204
205 #[test]
206 fn test_frame_access_on_frame_view() {
207 let frame = make_frame();
208 let view = FrameView::from(&frame);
209 assert!(FrameAccess::get_float(&view, "atoms", "x").is_some());
210 assert!(FrameAccess::get_int(&view, "atoms", "id").is_some());
211 assert!(FrameAccess::get_float(&view, "atoms", "missing").is_none());
212 assert_eq!(FrameAccess::block_count(&view), 1);
213 assert!(FrameAccess::contains_block(&view, "atoms"));
214 assert!(!FrameAccess::is_empty(&view));
215 assert_eq!(FrameAccess::meta_ref(&view).get("title").unwrap(), "Test");
216 }
217
218 #[test]
219 fn test_generic_function_with_frame_access() {
220 fn get_x_data(f: &impl FrameAccess) -> Option<Vec<F>> {
221 f.get_float("atoms", "x")
222 .map(|a| a.iter().copied().collect())
223 }
224
225 let frame = make_frame();
226 assert_eq!(get_x_data(&frame), Some(vec![1.0, 2.0, 3.0]));
227
228 let view = FrameView::from(&frame);
229 assert_eq!(get_x_data(&view), Some(vec![1.0, 2.0, 3.0]));
230 }
231}