use std::collections::HashMap;
use crate::spatial::region::simbox::SimBox;
use crate::store::block::block_view::BlockView;
use crate::store::frame::Frame;
pub struct FrameView<'a> {
map: HashMap<&'a str, BlockView<'a>>,
pub simbox: Option<&'a SimBox>,
pub meta: &'a HashMap<String, String>,
}
impl<'a> FrameView<'a> {
pub fn from_parts(
map: HashMap<&'a str, BlockView<'a>>,
simbox: Option<&'a SimBox>,
meta: &'a HashMap<String, String>,
) -> Self {
Self { map, simbox, meta }
}
#[inline]
pub fn get(&self, key: &str) -> Option<&BlockView<'a>> {
self.map.get(key)
}
pub fn iter(&self) -> impl Iterator<Item = (&&'a str, &BlockView<'a>)> {
self.map.iter()
}
pub fn keys(&self) -> impl Iterator<Item = &&'a str> {
self.map.keys()
}
pub fn values(&self) -> impl Iterator<Item = &BlockView<'a>> {
self.map.values()
}
#[inline]
pub fn len(&self) -> usize {
self.map.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
#[inline]
pub fn contains_key(&self, key: &str) -> bool {
self.map.contains_key(key)
}
pub fn to_owned(&self) -> Frame {
let mut block_map = HashMap::with_capacity(self.map.len());
for (&key, block_view) in &self.map {
block_map.insert(key.to_string(), block_view.to_owned());
}
let mut frame = Frame::from_map(block_map);
frame.simbox = self.simbox.cloned();
frame.meta = self.meta.clone();
frame
}
}
impl<'a> From<&'a Frame> for FrameView<'a> {
fn from(frame: &'a Frame) -> Self {
let mut map = HashMap::with_capacity(frame.len());
for (key, block) in frame.iter() {
map.insert(key, BlockView::from(block));
}
FrameView {
map,
simbox: frame.simbox.as_ref(),
meta: &frame.meta,
}
}
}
impl std::fmt::Debug for FrameView<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut debug_struct = f.debug_struct("FrameView");
let mut blocks_map = std::collections::BTreeMap::new();
for (&k, b) in &self.map {
blocks_map.insert(k, (b.nrows(), b.len()));
}
debug_struct.field("blocks", &blocks_map);
if !self.meta.is_empty() {
debug_struct.field("meta", &self.meta);
}
debug_struct.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::store::block::Block;
use crate::types::{F, I};
use ndarray::Array1;
fn make_frame() -> Frame {
let mut frame = Frame::new();
let mut atoms = Block::new();
atoms
.insert("x", Array1::from_vec(vec![1.0 as F, 2.0, 3.0]).into_dyn())
.unwrap();
atoms
.insert("id", Array1::from_vec(vec![10 as I, 20, 30]).into_dyn())
.unwrap();
frame.insert("atoms", atoms);
let mut bonds = Block::new();
bonds
.insert("type", Array1::from_vec(vec![1 as I, 2]).into_dyn())
.unwrap();
frame.insert("bonds", bonds);
frame.meta.insert("title".into(), "Test".into());
frame
}
#[test]
fn test_from_frame() {
let frame = make_frame();
let view = FrameView::from(&frame);
assert_eq!(view.len(), 2);
assert!(view.contains_key("atoms"));
assert!(view.contains_key("bonds"));
assert!(!view.is_empty());
}
#[test]
fn test_get_block_view() {
let frame = make_frame();
let view = FrameView::from(&frame);
let atoms = view.get("atoms").unwrap();
assert_eq!(atoms.nrows(), Some(3));
assert!(atoms.get_float("x").is_some());
}
#[test]
fn test_meta_borrowed() {
let frame = make_frame();
let view = FrameView::from(&frame);
assert_eq!(view.meta.get("title").unwrap(), "Test");
}
#[test]
fn test_simbox_none() {
let frame = make_frame();
let view = FrameView::from(&frame);
assert!(view.simbox.is_none());
}
#[test]
fn test_to_owned_roundtrip() {
let frame = make_frame();
let view = FrameView::from(&frame);
let owned = view.to_owned();
assert_eq!(owned.len(), 2);
assert!(owned.contains_key("atoms"));
assert!(owned.contains_key("bonds"));
assert_eq!(owned.meta.get("title").unwrap(), "Test");
let atoms = owned.get("atoms").unwrap();
assert_eq!(atoms.nrows(), Some(3));
assert_eq!(
atoms
.get_float("x")
.unwrap()
.as_slice_memory_order()
.unwrap(),
&[1.0, 2.0, 3.0]
);
}
#[test]
fn test_iter_keys() {
let frame = make_frame();
let view = FrameView::from(&frame);
let keys: Vec<&&str> = view.keys().collect();
assert_eq!(keys.len(), 2);
let mut count = 0;
for (_name, _block) in view.iter() {
count += 1;
}
assert_eq!(count, 2);
}
#[test]
fn test_zero_copy() {
let frame = make_frame();
let view = FrameView::from(&frame);
let orig_ptr = frame.get("atoms").unwrap().get_float("x").unwrap().as_ptr();
let view_ptr = view.get("atoms").unwrap().get_float("x").unwrap().as_ptr();
assert_eq!(orig_ptr, view_ptr);
}
}