use core::fmt::Debug;
use alloc::boxed::Box;
use crate::{
ConstString,
any_port_value::AnyPortValue,
bind::{
BindCommons,
bound_value::{BoundValueReadGuard, BoundValueWriteGuard},
},
error::Error,
port_variant::PortVariant,
};
pub mod port_array;
pub mod port_map;
pub mod port_vec;
use crate::collections::port_array::PortArray;
pub struct EmptyPortArray(core::cell::UnsafeCell<PortArray<0>>);
#[allow(unsafe_code)]
unsafe impl Sync for EmptyPortArray {}
impl EmptyPortArray {
const fn new() -> Self {
Self(core::cell::UnsafeCell::new(PortArray([])))
}
pub fn get(&self) -> &PortArray<0> {
#[allow(unsafe_code)]
unsafe {
&*self.0.get()
}
}
#[allow(clippy::mut_from_ref)]
pub fn get_mut(&self) -> &mut PortArray<0> {
#[allow(unsafe_code)]
unsafe {
&mut *self.0.get()
}
}
}
pub static EMPTY_PORT_ARRAY: EmptyPortArray = EmptyPortArray::new();
pub trait PortList: PortCollection + PortCollectionAccessorsCommon {}
impl<T: PortCollection + PortCollectionAccessorsCommon> PortList for T {}
pub trait PortCollection: Debug {
fn find(&self, name: &str) -> Option<&PortVariant>;
fn find_mut(&mut self, name: &str) -> Option<&mut PortVariant>;
fn set_from_str(&mut self, name: &str, value: &str) -> Result<(), Error>;
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (&'a str, &'a PortVariant)> + 'a>;
fn iter_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = (&'a str, &'a mut PortVariant)> + 'a>;
}
pub trait PortCollectionMut: PortCollection {
fn add(&mut self, name: ConstString, port: PortVariant) -> Result<(), Error>;
fn delete(&mut self, name: &str) -> Result<PortVariant, Error>;
}
pub trait PortCollectionAccessorsCommon {
fn contains_name(&self, name: &str) -> bool;
fn give_to_bound(&self, name: &str, bound: &mut dyn BindCommons) -> Result<(), Error>;
fn give_to_collection(
&self,
name: &str,
other_collection: &mut dyn PortCollection,
other_name: &str,
) -> Result<(), Error>;
fn give_to_variant(&self, name: &str, variant: &mut PortVariant) -> Result<(), Error>;
fn sequence_number(&self, name: &str) -> Result<u32, Error>;
fn use_from_bound(&mut self, name: &str, bound: &dyn BindCommons) -> Result<(), Error>;
fn use_from_collection(
&mut self,
name: &str,
other_collection: &dyn PortCollection,
other_name: &str,
) -> Result<(), Error>;
fn use_from_variant(&mut self, name: &str, variant: &PortVariant) -> Result<(), Error>;
}
pub trait PortCollectionAccessors: PortCollectionAccessorsCommon {
fn contains<T: AnyPortValue>(&self, name: &str) -> Result<bool, Error>;
fn get<T>(&self, name: &str) -> Result<T, Error>
where
T: AnyPortValue + Clone;
fn read<T: AnyPortValue>(&self, name: &str) -> Result<BoundValueReadGuard<T>, Error>;
fn try_read<T: AnyPortValue>(&self, name: &str) -> Result<BoundValueReadGuard<T>, Error>;
fn replace<T: AnyPortValue>(&mut self, name: &str, value: T) -> Result<Option<T>, Error>;
fn set<T: AnyPortValue>(&mut self, name: &str, value: T) -> Result<(), Error>;
fn take<T: AnyPortValue>(&mut self, name: &str) -> Result<Option<T>, Error>;
fn write<T: AnyPortValue>(&mut self, name: &str) -> Result<BoundValueWriteGuard<T>, Error>;
fn try_write<T: AnyPortValue>(&mut self, name: &str) -> Result<BoundValueWriteGuard<T>, Error>;
}
pub trait PortCollectionProvider {
fn provided_ports(&self) -> &impl PortCollectionAccessors {
EMPTY_PORT_ARRAY.get()
}
fn provided_ports_mut(&mut self) -> &mut impl PortCollectionAccessors {
EMPTY_PORT_ARRAY.get_mut()
}
fn port_collection(&self) -> &impl PortCollection {
EMPTY_PORT_ARRAY.get()
}
}
pub trait PortCollectionProviderMut: PortCollectionProvider {
fn port_collection_mut(&mut self) -> &mut impl PortCollectionMut;
}
#[cfg(test)]
mod tests {
use super::*;
const fn is_normal<T: Sized + Send + Sync>() {}
#[test]
const fn normal_types() {
is_normal::<&EmptyPortArray>();
is_normal::<EmptyPortArray>();
}
#[test]
fn get_returns_empty_array() {
let array = EMPTY_PORT_ARRAY.get();
assert!(array.is_empty());
assert!(array.find("any").is_none());
}
#[test]
fn get_mut_returns_empty_array() {
let array = EMPTY_PORT_ARRAY.get_mut();
assert!(array.is_empty());
assert!(array.find_mut("any").is_none());
}
#[test]
fn get_mut_set_from_str_returns_not_found() {
let array = EMPTY_PORT_ARRAY.get_mut();
assert_eq!(array.set_from_str("any", "42"), Err(Error::NotFound { name: "any".into() }));
}
#[test]
fn get_contains_name_returns_false() {
let array = EMPTY_PORT_ARRAY.get();
assert!(!array.contains_name("any"));
}
#[test]
fn get_sequence_number_returns_not_found() {
let array = EMPTY_PORT_ARRAY.get();
assert_eq!(array.sequence_number("any"), Err(Error::NotFound { name: "any".into() }));
}
#[test]
fn get_read_returns_error() {
let array = EMPTY_PORT_ARRAY.get();
assert!(array.read::<i32>("any").is_err());
}
#[test]
fn get_mut_write_returns_error() {
let array = EMPTY_PORT_ARRAY.get_mut();
assert!(array.write::<i32>("any").is_err());
}
#[test]
fn get_mut_set_returns_not_found() {
let array = EMPTY_PORT_ARRAY.get_mut();
assert_eq!(array.set::<i32>("any", 42), Err(Error::NotFound { name: "any".into() }));
}
#[test]
fn new_creates_empty_array() {
let empty = EmptyPortArray::new();
let array = empty.get();
assert!(array.is_empty());
}
#[test]
fn get_try_read_returns_error() {
let array = EMPTY_PORT_ARRAY.get();
assert!(array.try_read::<i32>("any").is_err());
}
#[test]
fn get_mut_try_write_returns_error() {
let array = EMPTY_PORT_ARRAY.get_mut();
assert!(array.try_write::<i32>("any").is_err());
}
#[test]
fn get_contains_returns_ok_false() {
let array = EMPTY_PORT_ARRAY.get();
assert_eq!(array.contains::<i32>("any"), Ok(false));
}
#[test]
fn get_get_returns_not_found() {
let array = EMPTY_PORT_ARRAY.get();
assert_eq!(array.get::<i32>("any"), Err(Error::NotFound { name: "any".into() }));
}
#[test]
fn get_mut_replace_returns_not_found() {
let array = EMPTY_PORT_ARRAY.get_mut();
assert_eq!(array.replace::<i32>("any", 42), Err(Error::NotFound { name: "any".into() }));
}
#[test]
fn get_mut_take_returns_not_found() {
let array = EMPTY_PORT_ARRAY.get_mut();
assert_eq!(array.take::<i32>("any"), Err(Error::NotFound { name: "any".into() }));
}
#[test]
fn get_give_to_variant_returns_not_found() {
let array = EMPTY_PORT_ARRAY.get();
let mut variant = PortVariant::create_inbound(0i32);
assert_eq!(
array.give_to_variant("any", &mut variant),
Err(Error::NotFound { name: "any".into() })
);
}
#[test]
fn get_give_to_bound_returns_not_found() {
use crate::bind::in_::InBound;
let array = EMPTY_PORT_ARRAY.get();
let mut port = InBound::with_value(42i32);
assert_eq!(
array.give_to_bound("any", &mut port),
Err(Error::NotFound { name: "any".into() })
);
}
#[test]
fn get_give_to_collection_returns_not_found() {
let array = EMPTY_PORT_ARRAY.get();
let mut other = crate::collections::port_array::PortArray::<0>::empty();
assert_eq!(
array.give_to_collection("any", &mut other, "other"),
Err(Error::NotFound { name: "any".into() })
);
}
#[test]
fn get_mut_use_from_variant_returns_not_found() {
let array = EMPTY_PORT_ARRAY.get_mut();
let variant = PortVariant::create_inbound(0i32);
assert_eq!(
array.use_from_variant("any", &variant),
Err(Error::NotFound { name: "any".into() })
);
}
#[test]
fn get_mut_use_from_bound_returns_not_found() {
use crate::bind::in_::InBound;
let array = EMPTY_PORT_ARRAY.get_mut();
let port = InBound::with_value(42i32);
assert_eq!(
array.use_from_bound("any", &port),
Err(Error::NotFound { name: "any".into() })
);
}
#[test]
fn get_mut_use_from_collection_returns_not_found() {
let array = EMPTY_PORT_ARRAY.get_mut();
let other = crate::collections::port_array::PortArray::<0>::empty();
assert_eq!(
array.use_from_collection("any", &other, "other"),
Err(Error::NotFound { name: "any".into() })
);
}
}