1use std::collections::HashMap;
8
9use crate::block::block_view::BlockView;
10use crate::frame::Frame;
11use crate::region::simbox::SimBox;
12
13pub struct FrameView<'a> {
19 map: HashMap<&'a str, BlockView<'a>>,
20 pub simbox: Option<&'a SimBox>,
22 pub meta: &'a HashMap<String, String>,
24}
25
26impl<'a> FrameView<'a> {
27 pub fn from_parts(
29 map: HashMap<&'a str, BlockView<'a>>,
30 simbox: Option<&'a SimBox>,
31 meta: &'a HashMap<String, String>,
32 ) -> Self {
33 Self { map, simbox, meta }
34 }
35
36 #[inline]
38 pub fn get(&self, key: &str) -> Option<&BlockView<'a>> {
39 self.map.get(key)
40 }
41
42 pub fn iter(&self) -> impl Iterator<Item = (&&'a str, &BlockView<'a>)> {
44 self.map.iter()
45 }
46
47 pub fn keys(&self) -> impl Iterator<Item = &&'a str> {
49 self.map.keys()
50 }
51
52 pub fn values(&self) -> impl Iterator<Item = &BlockView<'a>> {
54 self.map.values()
55 }
56
57 #[inline]
59 pub fn len(&self) -> usize {
60 self.map.len()
61 }
62
63 #[inline]
65 pub fn is_empty(&self) -> bool {
66 self.map.is_empty()
67 }
68
69 #[inline]
71 pub fn contains_key(&self, key: &str) -> bool {
72 self.map.contains_key(key)
73 }
74
75 pub fn to_owned(&self) -> Frame {
77 let mut block_map = HashMap::with_capacity(self.map.len());
78 for (&key, block_view) in &self.map {
79 block_map.insert(key.to_string(), block_view.to_owned());
80 }
81 let mut frame = Frame::from_map(block_map);
82 frame.simbox = self.simbox.cloned();
83 frame.meta = self.meta.clone();
84 frame
85 }
86}
87
88impl<'a> From<&'a Frame> for FrameView<'a> {
89 fn from(frame: &'a Frame) -> Self {
90 let mut map = HashMap::with_capacity(frame.len());
91 for (key, block) in frame.iter() {
92 map.insert(key, BlockView::from(block));
93 }
94 FrameView {
95 map,
96 simbox: frame.simbox.as_ref(),
97 meta: &frame.meta,
98 }
99 }
100}
101
102impl std::fmt::Debug for FrameView<'_> {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 let mut debug_struct = f.debug_struct("FrameView");
105
106 let mut blocks_map = std::collections::BTreeMap::new();
107 for (&k, b) in &self.map {
108 blocks_map.insert(k, (b.nrows(), b.len()));
109 }
110 debug_struct.field("blocks", &blocks_map);
111
112 if !self.meta.is_empty() {
113 debug_struct.field("meta", &self.meta);
114 }
115
116 debug_struct.finish()
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123 use crate::block::Block;
124 use crate::types::{F, I};
125 use ndarray::Array1;
126
127 fn make_frame() -> Frame {
128 let mut frame = Frame::new();
129 let mut atoms = Block::new();
130 atoms
131 .insert("x", Array1::from_vec(vec![1.0 as F, 2.0, 3.0]).into_dyn())
132 .unwrap();
133 atoms
134 .insert("id", Array1::from_vec(vec![10 as I, 20, 30]).into_dyn())
135 .unwrap();
136 frame.insert("atoms", atoms);
137
138 let mut bonds = Block::new();
139 bonds
140 .insert("type", Array1::from_vec(vec![1 as I, 2]).into_dyn())
141 .unwrap();
142 frame.insert("bonds", bonds);
143
144 frame.meta.insert("title".into(), "Test".into());
145 frame
146 }
147
148 #[test]
149 fn test_from_frame() {
150 let frame = make_frame();
151 let view = FrameView::from(&frame);
152 assert_eq!(view.len(), 2);
153 assert!(view.contains_key("atoms"));
154 assert!(view.contains_key("bonds"));
155 assert!(!view.is_empty());
156 }
157
158 #[test]
159 fn test_get_block_view() {
160 let frame = make_frame();
161 let view = FrameView::from(&frame);
162
163 let atoms = view.get("atoms").unwrap();
164 assert_eq!(atoms.nrows(), Some(3));
165 assert!(atoms.get_float("x").is_some());
166 }
167
168 #[test]
169 fn test_meta_borrowed() {
170 let frame = make_frame();
171 let view = FrameView::from(&frame);
172 assert_eq!(view.meta.get("title").unwrap(), "Test");
173 }
174
175 #[test]
176 fn test_simbox_none() {
177 let frame = make_frame();
178 let view = FrameView::from(&frame);
179 assert!(view.simbox.is_none());
180 }
181
182 #[test]
183 fn test_to_owned_roundtrip() {
184 let frame = make_frame();
185 let view = FrameView::from(&frame);
186 let owned = view.to_owned();
187
188 assert_eq!(owned.len(), 2);
189 assert!(owned.contains_key("atoms"));
190 assert!(owned.contains_key("bonds"));
191 assert_eq!(owned.meta.get("title").unwrap(), "Test");
192
193 let atoms = owned.get("atoms").unwrap();
194 assert_eq!(atoms.nrows(), Some(3));
195 assert_eq!(
196 atoms
197 .get_float("x")
198 .unwrap()
199 .as_slice_memory_order()
200 .unwrap(),
201 &[1.0, 2.0, 3.0]
202 );
203 }
204
205 #[test]
206 fn test_iter_keys() {
207 let frame = make_frame();
208 let view = FrameView::from(&frame);
209
210 let keys: Vec<&&str> = view.keys().collect();
211 assert_eq!(keys.len(), 2);
212
213 let mut count = 0;
214 for (_name, _block) in view.iter() {
215 count += 1;
216 }
217 assert_eq!(count, 2);
218 }
219
220 #[test]
221 fn test_zero_copy() {
222 let frame = make_frame();
223 let view = FrameView::from(&frame);
224
225 let orig_ptr = frame.get("atoms").unwrap().get_float("x").unwrap().as_ptr();
226 let view_ptr = view.get("atoms").unwrap().get_float("x").unwrap().as_ptr();
227 assert_eq!(orig_ptr, view_ptr);
228 }
229}