use crate::{config::EmptyEnum, prelude::Pubtime};
use serde::{Deserialize, Serialize};
use std::hash::Hash;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum SignalDataType {
Bool,
Int64,
Usize,
Float64,
String,
}
pub trait SignalKind: 'static + Copy + PartialEq + Eq + Hash {
fn list() -> &'static [Self];
fn dtype(&self) -> SignalDataType;
fn as_str(&self) -> &'static str;
fn from_str(id: &str) -> Option<Self>;
fn to_string(self) -> String {
self.as_str().into()
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum SignalValue {
Bool(bool),
Int64(i64),
Usize(usize),
Float64(f64),
String(String),
}
impl SignalValue {
pub fn dtype(&self) -> SignalDataType {
match self {
SignalValue::Bool(_) => SignalDataType::Bool,
SignalValue::Int64(_) => SignalDataType::Int64,
SignalValue::Usize(_) => SignalDataType::Usize,
SignalValue::Float64(_) => SignalDataType::Float64,
SignalValue::String(_) => SignalDataType::String,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SignalProperties {
pub dtype: SignalDataType,
}
pub trait Signals: Default + Send {
type Kind: SignalKind;
fn as_time_value_iter(
&self,
) -> impl Iterator<Item = Option<SignalTimeValue>> + ExactSizeIterator;
fn on_post_execute(&mut self, step_time: Pubtime);
fn names() -> impl Iterator<Item = &'static str> {
Self::Kind::list().iter().map(|k| k.as_str())
}
}
impl SignalKind for EmptyEnum {
fn list() -> &'static [Self] {
&[]
}
fn dtype(&self) -> SignalDataType {
unreachable!()
}
fn from_str(_id: &str) -> Option<Self> {
None
}
fn as_str(&self) -> &'static str {
unreachable!()
}
}
impl Signals for () {
type Kind = EmptyEnum;
fn as_time_value_iter(
&self,
) -> impl Iterator<Item = Option<SignalTimeValue>> + ExactSizeIterator {
std::iter::empty()
}
fn on_post_execute(&mut self, _: Pubtime) {}
}
#[derive(Debug, Clone)]
pub struct SignalCell<T> {
last_set_time: Option<Pubtime>,
value: Option<T>,
dirty: bool,
}
impl<T> Default for SignalCell<T> {
fn default() -> Self {
Self {
last_set_time: None,
value: None,
dirty: true,
}
}
}
impl<T> SignalCell<T> {
#[inline]
pub fn set(&mut self, value: T) {
self.dirty = true;
self.value = Some(value);
}
#[inline]
pub fn clear(&mut self) {
self.dirty = true;
self.value = None;
}
#[inline]
pub fn on_post_execute(&mut self, time: Pubtime) {
if self.dirty {
self.dirty = false;
self.last_set_time = Some(time);
}
}
}
impl SignalCell<usize> {
#[inline]
pub fn increment(&mut self) {
self.add(1)
}
#[inline]
pub fn add(&mut self, n: usize) {
self.dirty = true;
self.value = self.value.map(|v| v + n).or(Some(n));
}
}
pub trait SignalCellCore {
fn last_set_time(&self) -> Option<Pubtime>;
}
impl<T> SignalCellCore for SignalCell<T> {
#[inline]
fn last_set_time(&self) -> Option<Pubtime> {
self.last_set_time
}
}
pub trait SignalCellAnon: SignalCellCore {
fn value_anon(&self) -> Option<SignalValue>;
#[inline]
fn anon_time_value(&self) -> Option<SignalTimeValue> {
match (self.last_set_time(), self.value_anon()) {
(Some(time), Some(value)) => Some(SignalTimeValue { time, value }),
(None, None) => None,
_ => None,
}
}
}
impl SignalCellAnon for SignalCell<bool> {
#[inline]
fn value_anon(&self) -> Option<SignalValue> {
self.value.map(|v| SignalValue::Bool(v))
}
}
impl SignalCellAnon for SignalCell<i64> {
#[inline]
fn value_anon(&self) -> Option<SignalValue> {
self.value.map(|v| SignalValue::Int64(v))
}
}
impl SignalCellAnon for SignalCell<usize> {
#[inline]
fn value_anon(&self) -> Option<SignalValue> {
self.value.map(|v| SignalValue::Usize(v))
}
}
impl SignalCellAnon for SignalCell<f64> {
#[inline]
fn value_anon(&self) -> Option<SignalValue> {
self.value.map(|v| SignalValue::Float64(v))
}
}
impl SignalCellAnon for SignalCell<String> {
#[inline]
fn value_anon(&self) -> Option<SignalValue> {
self.value.clone().map(|v| SignalValue::String(v))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignalTimeValue {
pub time: Pubtime,
pub value: SignalValue,
}