use std::any::{Any, type_name};
use std::fmt;
use super::error::StateError;
use super::spec::{FieldSpec, StateSpec};
use super::value::StateValue;
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct TimePoint {
index: u64,
physical: Option<f64>,
}
impl TimePoint {
pub const fn new(index: u64) -> Self {
Self {
index,
physical: None,
}
}
pub fn from_physical(index: u64, physical: f64) -> Option<Self> {
physical.is_finite().then_some(Self {
index,
physical: Some(physical),
})
}
pub const fn index(self) -> u64 {
self.index
}
pub const fn physical(self) -> Option<f64> {
self.physical
}
}
pub struct SystemState {
spec: StateSpec,
time: TimePoint,
values: Vec<Option<StateValue>>,
}
impl SystemState {
pub(crate) fn new(spec: StateSpec, time: TimePoint) -> Self {
let values = (0..spec.len()).map(|_| None).collect();
Self { spec, time, values }
}
pub fn empty(&self, time: TimePoint) -> Self {
Self::new(self.spec.clone(), time)
}
pub const fn time(&self) -> TimePoint {
self.time
}
pub const fn spec(&self) -> &StateSpec {
&self.spec
}
pub fn len(&self) -> usize {
self.values.len()
}
pub fn is_empty(&self) -> bool {
self.values.is_empty()
}
pub fn loaded(&self) -> usize {
self.values.iter().filter(|value| value.is_some()).count()
}
pub fn is_blank(&self) -> bool {
self.values.iter().all(Option::is_none)
}
pub fn fields(&self) -> &[FieldSpec] {
self.spec.fields()
}
pub fn has(&self, key: &str) -> Result<bool, StateError> {
let index = self.spec.index_of(key)?;
Ok(self.values[index].is_some())
}
pub fn is<T>(&self, key: &str) -> Result<bool, StateError>
where
T: Any,
{
let index = self.spec.index_of(key)?;
Ok(self.values[index].as_ref().is_some_and(StateValue::is::<T>))
}
pub fn set<T>(&mut self, key: &str, payload: T) -> Result<(), StateError>
where
T: Any + Clone + Send,
{
let index = self.spec.index_of(key)?;
self.values[index] = Some(StateValue::new(payload));
Ok(())
}
pub fn get<T>(&self, key: &str) -> Result<&T, StateError>
where
T: Any,
{
let value = self.value(key)?;
let actual = value.type_name();
value
.downcast_ref::<T>()
.ok_or_else(|| StateError::TypeMismatch {
field: key.to_owned(),
expected: type_name::<T>(),
actual,
})
}
pub fn get_mut<T>(&mut self, key: &str) -> Result<&mut T, StateError>
where
T: Any,
{
let value = self.value_mut(key)?;
let actual = value.type_name();
value
.downcast_mut::<T>()
.ok_or_else(|| StateError::TypeMismatch {
field: key.to_owned(),
expected: type_name::<T>(),
actual,
})
}
pub fn take<T>(&mut self, key: &str) -> Result<T, StateError>
where
T: Any + Send,
{
let index = self.spec.index_of(key)?;
let value = self.values[index]
.take()
.ok_or_else(|| StateError::MissingValue {
field: key.to_owned(),
})?;
let actual = value.type_name();
match value.downcast::<T>() {
Ok(payload) => Ok(payload),
Err(value) => {
self.values[index] = Some(value);
Err(StateError::TypeMismatch {
field: key.to_owned(),
expected: type_name::<T>(),
actual,
})
}
}
}
pub fn clear(&mut self, key: &str) -> Result<bool, StateError> {
let index = self.spec.index_of(key)?;
Ok(self.values[index].take().is_some())
}
pub fn clear_all(&mut self) {
self.values.iter_mut().for_each(|value| *value = None);
}
fn value(&self, key: &str) -> Result<&StateValue, StateError> {
let index = self.spec.index_of(key)?;
self.values[index]
.as_ref()
.ok_or_else(|| StateError::MissingValue {
field: key.to_owned(),
})
}
fn value_mut(&mut self, key: &str) -> Result<&mut StateValue, StateError> {
let index = self.spec.index_of(key)?;
self.values[index]
.as_mut()
.ok_or_else(|| StateError::MissingValue {
field: key.to_owned(),
})
}
}
impl Clone for SystemState {
fn clone(&self) -> Self {
Self {
spec: self.spec.clone(),
time: self.time,
values: self.values.clone(),
}
}
}
impl fmt::Debug for SystemState {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("SystemState")
.field("time", &self.time)
.field("source", &self.spec.source())
.field("fields", &self.len())
.field("loaded", &self.loaded())
.finish_non_exhaustive()
}
}