use thiserror::Error;
use crate::prelude::*;
#[derive(Error, Debug)]
pub enum StateError {
#[error("velocities are not present in the current state")]
NoVelocities,
#[error("forces are not present in the current state")]
NoForces,
}
#[derive(Debug, Default, Clone)]
pub struct State {
pub coords: Vec<Pos>,
pub velocities: Vec<Vel>,
pub forces: Vec<Force>,
pub time: f32,
pub pbox: Option<PeriodicBox>,
}
impl State {
pub fn has_pos(&self) -> bool { !self.coords.is_empty() }
pub fn has_vel(&self) -> bool { !self.velocities.is_empty() }
pub fn has_force(&self) -> bool { !self.forces.is_empty() }
}
impl State {
pub fn add_coords(&mut self, pos: impl Iterator<Item = Pos>) {
self.coords.extend(pos);
}
pub fn remove_coords(
&mut self,
removed: impl Iterator<Item = usize>,
) -> Result<(), BuilderError> {
let mut ind = removed.collect::<Vec<_>>();
if ind.len() == 0 {
return Ok(());
}
ind.sort_unstable();
ind.dedup();
if ind[0] >= self.coords.len() || ind[ind.len() - 1] >= self.coords.len() {
return Err(BuilderError::RemoveIndexes(
ind[0],
ind[ind.len() - 1],
self.coords.len(),
));
}
macro_rules! retain_not_in {
($vec:expr) => {
if !$vec.is_empty() {
let mut it = ind.iter().cloned();
let mut to_remove = it.next().unwrap_or(usize::MAX);
let mut i = 0usize;
$vec.retain(|_| {
let ok = i != to_remove;
i += 1;
if !ok { to_remove = it.next().unwrap_or(usize::MAX); }
ok
});
}
};
}
retain_not_in!(self.coords);
retain_not_in!(self.velocities);
retain_not_in!(self.forces);
Ok(())
}
}
impl State {
pub fn interchangeable(&self, other: &State) -> bool {
self.coords.len() == other.coords.len()
}
pub fn new_fake(n: usize) -> Self {
Self {
coords: vec![Pos::origin(); n],
velocities: Vec::new(),
forces: Vec::new(),
pbox: None,
time: 0.0,
}
}
}
impl SaveState for State {
fn iter_pos_dyn<'a>(&'a self) -> Box<dyn ExactSizeIterator<Item = &'a Pos> + 'a> {
Box::new(self.coords.iter())
}
fn iter_vel_dyn<'a>(&'a self) -> Box<dyn ExactSizeIterator<Item = &'a Vel> + 'a> {
Box::new(self.velocities.iter())
}
fn iter_force_dyn<'a>(&'a self) -> Box<dyn ExactSizeIterator<Item = &'a Force> + 'a> {
Box::new(self.forces.iter())
}
}
impl TimeProvider for State {
fn get_time(&self) -> f32 {
self.time
}
}
impl TimeMutProvider for State {
fn set_time(&mut self, t: f32) {
self.time = t;
}
}
impl LenProvider for State {
fn len(&self) -> usize {
let n = self.coords.len();
if n > 0 { return n; }
let n = self.velocities.len();
if n > 0 { return n; }
self.forces.len()
}
}
impl IndexProvider for State {
unsafe fn get_index_unchecked(&self, i: usize) -> usize {
i
}
fn iter_index(&self) -> impl ExactSizeIterator<Item = usize> {
0..self.coords.len()
}
}
impl PosProvider for State {
unsafe fn coords_ptr(&self) -> *const Pos {
self.coords.as_ptr()
}
}
impl PosMutProvider for State {
unsafe fn coords_ptr_mut(&mut self) -> *mut Pos {
self.coords.as_mut_ptr()
}
}
impl BoxProvider for State {
fn get_box(&self) -> Option<&PeriodicBox> {
self.pbox.as_ref()
}
}
impl BoxMutProvider for State {
fn get_box_mut(&mut self) -> Option<&mut PeriodicBox> {
self.pbox.as_mut()
}
}
impl VelProvider for State {
unsafe fn vel_ptr(&self) -> *const Vel {
if self.velocities.is_empty() { std::ptr::null() } else { self.velocities.as_ptr() }
}
}
impl VelMutProvider for State {
unsafe fn vel_ptr_mut(&mut self) -> *mut Vel {
if self.velocities.is_empty() { std::ptr::null_mut() } else { self.velocities.as_mut_ptr() }
}
}
impl ForceProvider for State {
unsafe fn force_ptr(&self) -> *const Force {
if self.forces.is_empty() { std::ptr::null() } else { self.forces.as_ptr() }
}
}
impl ForceMutProvider for State {
unsafe fn force_ptr_mut(&mut self) -> *mut Force {
if self.forces.is_empty() { std::ptr::null_mut() } else { self.forces.as_mut_ptr() }
}
}