use crate::DynRef;
use std::{any::Any, cell::UnsafeCell, ops::Deref, str::FromStr, sync::Arc};
pub trait PortVal: DynRef + Clone + FromStr + ToString {}
impl<T: DynRef + Clone + FromStr + ToString> PortVal for T {}
pub(crate) trait Port: DynRef {
fn as_any(&self) -> &dyn Any;
unsafe fn is_empty(&self) -> bool;
unsafe fn clear(&self);
fn is_compatible(&self, other: &dyn Port) -> bool;
unsafe fn propagate(&self, port_to: &dyn Port);
#[cfg(feature = "rt")]
unsafe fn inject(&self, value: &str) -> Result<(), ()>;
#[cfg(feature = "rt")]
unsafe fn eject(&self) -> Vec<String>;
}
#[derive(Debug)]
pub(super) struct Bag<T>(UnsafeCell<Vec<T>>);
impl<T> Bag<T> {
#[inline]
pub(super) fn new() -> Arc<Self> {
Arc::new(Self(UnsafeCell::new(Vec::new())))
}
#[inline]
unsafe fn borrow(&self) -> &Vec<T> {
&*self.get()
}
#[allow(clippy::mut_from_ref)]
#[inline]
unsafe fn borrow_mut(&self) -> &mut Vec<T> {
&mut *self.get()
}
}
impl<T> Deref for Bag<T> {
type Target = UnsafeCell<Vec<T>>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(any(feature = "par_any", feature = "rt"))]
unsafe impl<T: Send> Send for Bag<T> {}
#[cfg(any(feature = "par_any", feature = "rt"))]
unsafe impl<T: Sync> Sync for Bag<T> {}
impl<T: PortVal> Port for Bag<T> {
#[inline]
fn as_any(&self) -> &dyn Any {
self
}
#[inline]
unsafe fn is_empty(&self) -> bool {
self.borrow().is_empty()
}
#[inline]
unsafe fn clear(&self) {
self.borrow_mut().clear();
}
#[inline]
fn is_compatible(&self, other: &dyn Port) -> bool {
other.as_any().downcast_ref::<Bag<T>>().is_some()
}
#[inline]
unsafe fn propagate(&self, port_to: &dyn Port) {
let port_to = port_to.as_any().downcast_ref::<Bag<T>>().unwrap();
port_to.borrow_mut().extend_from_slice(self.borrow());
}
#[inline]
#[cfg(feature = "rt")]
unsafe fn inject(&self, value: &str) -> Result<(), ()> {
match value.parse() {
Ok(value) => {
self.borrow_mut().push(value);
Ok(())
}
Err(_) => Err(()),
}
}
#[inline]
#[cfg(feature = "rt")]
unsafe fn eject(&self) -> Vec<String> {
self.borrow_mut().iter().map(|v| v.to_string()).collect()
}
}
#[derive(Debug)]
pub struct InPort<T>(pub(super) Arc<Bag<T>>);
impl<T> InPort<T> {
#[inline]
pub unsafe fn is_empty(&self) -> bool {
self.0.borrow().is_empty()
}
#[inline]
pub unsafe fn get_values(&self) -> &[T] {
self.0.borrow()
}
}
#[derive(Debug)]
pub struct OutPort<T>(pub(super) Arc<Bag<T>>);
impl<T> OutPort<T> {
#[inline]
pub unsafe fn add_value(&self, value: T) {
self.0.borrow_mut().push(value);
}
#[inline]
pub unsafe fn add_values(&self, values: &[T])
where
T: Clone,
{
self.0.borrow_mut().extend_from_slice(values);
}
}