use std::any::Any;
use std::error::Error;
use std::fmt;
use crate::system_state::{SystemState, SystemStateSchema};
use super::error::StateSeriesError;
pub struct StateSeries {
spec: SystemStateSchema,
states: Vec<SystemState>,
}
impl StateSeries {
pub fn new(spec: SystemStateSchema) -> Self {
Self {
spec,
states: Vec::new(),
}
}
pub fn with_capacity(spec: SystemStateSchema, capacity: usize) -> Self {
Self {
spec,
states: Vec::with_capacity(capacity),
}
}
pub fn schema(&self) -> &SystemStateSchema {
&self.spec
}
pub fn as_view(&self) -> StateSeriesView<'_> {
StateSeriesView::new(&self.spec, &self.states)
}
pub fn len(&self) -> usize {
self.states.len()
}
pub fn is_empty(&self) -> bool {
self.states.is_empty()
}
pub fn capacity(&self) -> usize {
self.states.capacity()
}
pub fn reserve(&mut self, additional: usize) {
self.states.reserve(additional);
}
pub fn state_at(&self, position: usize) -> Option<&SystemState> {
self.states.get(position)
}
pub fn payload_mut_at<T>(
&mut self,
position: usize,
key: &str,
) -> Result<&mut T, StateSeriesError>
where
T: Any,
{
let len = self.states.len();
let state = self
.states
.get_mut(position)
.ok_or(StateSeriesError::PositionOutOfBounds { position, len })?;
state
.payload_mut::<T>(key)
.map_err(|source| StateSeriesError::PayloadAccess { position, source })
}
pub fn first_state(&self) -> Option<&SystemState> {
self.states.first()
}
pub fn last_state(&self) -> Option<&SystemState> {
self.states.last()
}
pub fn as_state_slice(&self) -> &[SystemState] {
&self.states
}
pub fn iter(&self) -> std::slice::Iter<'_, SystemState> {
self.states.iter()
}
pub fn push_state(&mut self, state: SystemState) -> Result<(), StateSeriesPushError> {
if !self.spec.shares_schema_instance(state.schema()) {
return Err(StateSeriesPushError::new(
StateSeriesError::SchemaMismatch {
iteration: state.simulation_time().iteration(),
},
state,
));
}
if let Some(previous) = self
.last_state()
.map(|state| state.simulation_time().iteration())
{
let next = state.simulation_time().iteration();
if next <= previous {
return Err(StateSeriesPushError::new(
StateSeriesError::NonIncreasingIteration { previous, next },
state,
));
}
}
self.states.push(state);
Ok(())
}
pub fn pop_state(&mut self) -> Option<SystemState> {
self.states.pop()
}
pub fn clear_states(&mut self) {
self.states.clear();
}
pub fn into_states(self) -> Vec<SystemState> {
self.states
}
}
impl Clone for StateSeries {
fn clone(&self) -> Self {
Self {
spec: self.spec.clone(),
states: self.states.clone(),
}
}
}
impl fmt::Debug for StateSeries {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("StateSeries")
.field("source", &self.spec.template_path())
.field("states", &self.len())
.field(
"first_iteration",
&self
.first_state()
.map(|state| state.simulation_time().iteration()),
)
.field(
"last_iteration",
&self
.last_state()
.map(|state| state.simulation_time().iteration()),
)
.finish_non_exhaustive()
}
}
impl<'a> IntoIterator for &'a StateSeries {
type Item = &'a SystemState;
type IntoIter = std::slice::Iter<'a, SystemState>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl IntoIterator for StateSeries {
type Item = SystemState;
type IntoIter = std::vec::IntoIter<SystemState>;
fn into_iter(self) -> Self::IntoIter {
self.states.into_iter()
}
}
#[must_use = "a series view has no effect unless it is inspected"]
#[derive(Clone, Copy)]
pub struct StateSeriesView<'a> {
spec: &'a SystemStateSchema,
states: &'a [SystemState],
}
impl<'a> StateSeriesView<'a> {
fn new(spec: &'a SystemStateSchema, states: &'a [SystemState]) -> Self {
Self { spec, states }
}
pub fn schema(self) -> &'a SystemStateSchema {
self.spec
}
pub fn len(self) -> usize {
self.states.len()
}
pub fn is_empty(self) -> bool {
self.states.is_empty()
}
pub fn state_at(self, position: usize) -> Option<&'a SystemState> {
self.states.get(position)
}
pub fn first_state(self) -> Option<&'a SystemState> {
self.states.first()
}
pub fn last_state(self) -> Option<&'a SystemState> {
self.states.last()
}
pub fn as_state_slice(self) -> &'a [SystemState] {
self.states
}
pub fn iter(self) -> std::slice::Iter<'a, SystemState> {
self.states.iter()
}
}
impl fmt::Debug for StateSeriesView<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("StateSeriesView")
.field("source", &self.spec.template_path())
.field("states", &self.len())
.field(
"first_iteration",
&self
.first_state()
.map(|state| state.simulation_time().iteration()),
)
.field(
"last_iteration",
&self
.last_state()
.map(|state| state.simulation_time().iteration()),
)
.finish_non_exhaustive()
}
}
impl<'a> IntoIterator for StateSeriesView<'a> {
type Item = &'a SystemState;
type IntoIter = std::slice::Iter<'a, SystemState>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[must_use = "the rejected SystemState remains owned by this error until recovered or dropped"]
pub struct StateSeriesPushError {
error: StateSeriesError,
state: Box<SystemState>,
}
impl StateSeriesPushError {
fn new(error: StateSeriesError, state: SystemState) -> Self {
Self {
error,
state: Box::new(state),
}
}
pub fn error(&self) -> &StateSeriesError {
&self.error
}
pub fn state(&self) -> &SystemState {
&self.state
}
pub fn into_parts(self) -> (StateSeriesError, SystemState) {
(self.error, *self.state)
}
}
impl fmt::Debug for StateSeriesPushError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("StateSeriesPushError")
.field("error", &self.error)
.field("state", &self.state)
.finish_non_exhaustive()
}
}
impl fmt::Display for StateSeriesPushError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(&self.error, formatter)
}
}
impl Error for StateSeriesPushError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
Some(&self.error)
}
}