use crate::{HasElements, Isotope, SiteId};
pub trait HasIsotopes: HasElements {
fn isotope(&self, site: SiteId) -> Isotope;
#[inline]
fn isotopes(&self) -> impl Iterator<Item = (SiteId, Isotope)> + '_ {
self.sites().map(move |site| (site, self.isotope(site)))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Element, HasSites};
fn site(n: u32) -> SiteId {
SiteId::new(n).unwrap()
}
fn protium() -> Isotope {
Isotope::new(Element::new(1).unwrap(), 1).unwrap()
}
fn oxygen_16() -> Isotope {
Isotope::new(Element::new(8).unwrap(), 16).unwrap()
}
struct Bare {
sites: Vec<SiteId>,
isotopes: Vec<Isotope>,
}
impl HasSites for Bare {
fn sites(&self) -> impl Iterator<Item = SiteId> + '_ {
self.sites.iter().copied()
}
}
impl HasElements for Bare {
fn element(&self, site: SiteId) -> Element {
self.isotope(site).element()
}
}
impl HasIsotopes for Bare {
fn isotope(&self, site: SiteId) -> Isotope {
let i = self.sites.iter().position(|&s| s == site).unwrap();
self.isotopes[i]
}
}
struct Columnar {
sites: Vec<SiteId>,
isotopes: Vec<Isotope>,
}
impl HasSites for Columnar {
fn sites(&self) -> impl Iterator<Item = SiteId> + '_ {
self.sites.iter().copied()
}
}
impl HasElements for Columnar {
fn element(&self, site: SiteId) -> Element {
self.isotope(site).element()
}
}
impl HasIsotopes for Columnar {
fn isotope(&self, site: SiteId) -> Isotope {
let i = self.sites.iter().position(|&s| s == site).unwrap();
self.isotopes[i]
}
fn isotopes(&self) -> impl Iterator<Item = (SiteId, Isotope)> + '_ {
self.sites
.iter()
.copied()
.zip(self.isotopes.iter().copied())
}
}
fn water() -> Bare {
Bare {
sites: vec![site(1), site(2), site(3)],
isotopes: vec![oxygen_16(), protium(), protium()],
}
}
#[test]
fn isotope() {
let mol = water();
assert_eq!(mol.isotope(site(1)), oxygen_16());
assert_eq!(mol.isotope(site(2)), protium());
}
#[test]
fn isotopes() {
let mol = water();
assert_eq!(
mol.isotopes().collect::<Vec<_>>(),
vec![
(site(1), oxygen_16()),
(site(2), protium()),
(site(3), protium())
]
);
}
#[test]
fn isotopes_empty() {
let mol = Bare {
sites: vec![],
isotopes: vec![],
};
assert_eq!(mol.isotopes().count(), 0);
}
#[test]
fn override_matches_default() {
use std::collections::BTreeMap;
let sites = vec![site(1), site(2), site(3)];
let isotopes = vec![oxygen_16(), protium(), protium()];
let bare = Bare {
sites: sites.clone(),
isotopes: isotopes.clone(),
};
let columnar = Columnar { sites, isotopes };
let bare_isos: BTreeMap<_, _> = bare.isotopes().collect();
let columnar_isos: BTreeMap<_, _> = columnar.isotopes().collect();
assert_eq!(bare_isos, columnar_isos);
}
}