use core::ops::{Deref, DerefMut};
use alloc::{boxed::Box, vec::Vec};
use crate::{
ConstString,
any_port_value::AnyPortValue,
bind::{
BindCommons,
bound_value::{BoundValueReadGuard, BoundValueWriteGuard},
},
collections::{PortCollection, PortCollectionAccessors, PortCollectionAccessorsCommon, PortCollectionMut},
error::Error,
port_variant::PortVariant,
};
#[derive(Clone, Debug, Default)]
#[repr(transparent)]
pub struct PortVec(Vec<(ConstString, PortVariant)>);
impl PortVec {
pub fn with_capacity(size: usize) -> Self {
Self(Vec::with_capacity(size))
}
pub fn from_array<const N: usize>(array: [(ConstString, PortVariant); N]) -> Self {
Self(Vec::from(array))
}
pub fn inner(&self) -> &Vec<(ConstString, PortVariant)> {
&self.0
}
pub fn inner_mut(&mut self) -> &mut Vec<(ConstString, PortVariant)> {
&mut self.0
}
}
impl Deref for PortVec {
type Target = Vec<(ConstString, PortVariant)>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for PortVec {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl PortCollection for PortVec {
fn find(&self, name: &str) -> Option<&PortVariant> {
self.0
.iter()
.find(|port| &*port.0 == name)
.map(|v| &v.1 as _)
}
fn find_mut(&mut self, name: &str) -> Option<&mut PortVariant> {
self.0
.iter_mut()
.find(|port| &*port.0 == name)
.map(|v| &mut v.1 as _)
}
fn set_from_str(&mut self, name: &str, value: &str) -> Result<(), Error> {
if let Some(port) = self.find_mut(name) {
port.set_from_str(value)
} else {
Err(Error::NotFound { name: name.into() })
}
}
fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (&'a str, &'a PortVariant)> + 'a> {
Box::new(self.0.iter().map(|(name, port)| (&**name, port)))
}
fn iter_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = (&'a str, &'a mut PortVariant)> + 'a> {
Box::new(
self.0
.iter_mut()
.map(|(name, port)| (&**name, port)),
)
}
}
impl PortCollectionMut for PortVec {
fn add(&mut self, name: ConstString, port: PortVariant) -> Result<(), Error> {
if self.find(&name).is_some() {
Err(Error::AlreadyExists)
} else {
self.0.push((name, port));
Ok(())
}
}
fn delete(&mut self, name: &str) -> Result<PortVariant, Error> {
let name = name.into();
if let Some(index) = self.0.iter().position(|r| r.0 == name) {
Ok(self.0.remove(index).1)
} else {
Err(Error::NotFound { name })
}
}
}
impl PortCollectionAccessorsCommon for PortVec {
fn contains_name(&self, name: &str) -> bool {
self.find(name).is_some()
}
fn give_to_bound(&self, name: &str, bound: &mut dyn BindCommons) -> Result<(), Error> {
self.find(name)
.map_or(Err(Error::NotFound { name: name.into() }), |port| {
bound.use_from_variant(port)
})
}
fn give_to_collection(
&self,
name: &str,
other_collection: &mut dyn PortCollection,
other_name: &str,
) -> Result<(), Error> {
self.find(name)
.map_or(Err(Error::NotFound { name: name.into() }), |port| {
other_collection
.find_mut(other_name)
.map_or(Err(Error::OtherNotFound { name: other_name.into() }), |variant| {
variant.use_from_variant(port)
})
})
}
fn give_to_variant(&self, name: &str, variant: &mut PortVariant) -> Result<(), Error> {
self.find(name)
.map_or(Err(Error::NotFound { name: name.into() }), |port| {
variant.use_from_variant(port)
})
}
fn sequence_number(&self, name: &str) -> Result<u32, Error> {
if let Some(port) = self.find(name) {
Ok(port.sequence_number())
} else {
Err(Error::NotFound { name: name.into() })
}
}
fn use_from_bound(&mut self, name: &str, bound: &dyn BindCommons) -> Result<(), Error> {
self.find_mut(name)
.map_or(Err(Error::NotFound { name: name.into() }), |port| port.use_from_bound(bound))
}
fn use_from_collection(
&mut self,
name: &str,
other_collection: &dyn PortCollection,
other_name: &str,
) -> Result<(), Error> {
other_collection
.find(other_name)
.map_or(Err(Error::OtherNotFound { name: other_name.into() }), |other| {
self.use_from_variant(name, other)
})
}
fn use_from_variant(&mut self, name: &str, variant: &PortVariant) -> Result<(), Error> {
if let Some(self_port) = self.find_mut(name) {
self_port.use_from_variant(variant)
} else {
Err(Error::NotFound { name: name.into() })
}
}
}
impl PortCollectionAccessors for PortVec {
fn contains<T: AnyPortValue>(&self, name: &str) -> Result<bool, Error> {
if let Some(p) = self.find(name) {
if p.is::<T>() { Ok(true) } else { Err(Error::DataType) }
} else {
Ok(false)
}
}
fn get<T>(&self, name: &str) -> Result<T, Error>
where
T: AnyPortValue + Clone,
{
if let Some(port) = self.find(name) {
match port.get::<T>()? {
Some(t) => Ok(t),
None => Err(Error::NoValueSet),
}
} else {
Err(Error::NotFound { name: name.into() })
}
}
fn read<T: AnyPortValue>(&self, name: &str) -> Result<BoundValueReadGuard<T>, Error> {
if let Some(port) = self.find(name) {
port.read()
} else {
Err(Error::NotFound { name: name.into() })
}
}
fn try_read<T: AnyPortValue>(&self, name: &str) -> Result<BoundValueReadGuard<T>, Error> {
if let Some(port) = self.find(name) {
port.try_read()
} else {
Err(Error::NotFound { name: name.into() })
}
}
fn replace<T: AnyPortValue>(&mut self, name: &str, value: T) -> Result<Option<T>, Error> {
if let Some(port) = self.find_mut(name) {
port.replace(value)
} else {
Err(Error::NotFound { name: name.into() })
}
}
fn set<T: AnyPortValue>(&mut self, name: &str, value: T) -> Result<(), Error> {
if let Some(port) = self.find_mut(name) {
port.set(value)
} else {
Err(Error::NotFound { name: name.into() })
}
}
fn take<T: AnyPortValue>(&mut self, name: &str) -> Result<Option<T>, Error> {
if let Some(port) = self.find_mut(name) {
port.take()
} else {
Err(Error::NotFound { name: name.into() })
}
}
fn write<T: AnyPortValue>(&mut self, name: &str) -> Result<BoundValueWriteGuard<T>, Error> {
if let Some(port) = self.find_mut(name) {
port.write()
} else {
Err(Error::NotFound { name: name.into() })
}
}
fn try_write<T: AnyPortValue>(&mut self, name: &str) -> Result<BoundValueWriteGuard<T>, Error> {
if let Some(port) = self.find_mut(name) {
port.try_write()
} else {
Err(Error::NotFound { name: name.into() })
}
}
}
#[cfg(test)]
mod tests {
use super::*;
const fn is_normal<T: Sized + Send + Sync>() {}
#[test]
const fn normal_types() {
is_normal::<&PortVec>();
is_normal::<PortVec>();
}
#[test]
fn insert_duplicate_name_returns_already_exists() {
let mut vec = PortVec::default();
let port = crate::PortVariant::create_outbound(42i32);
assert!(vec.add("dup".into(), port).is_ok());
let port2 = crate::PortVariant::create_inbound(0i32);
assert_eq!(vec.add("dup".into(), port2), Err(crate::error::Error::AlreadyExists));
}
#[test]
fn set_from_str_existing_port() {
let mut vec = PortVec::default();
let port = crate::PortVariant::create_outbound_parseable(0i32);
vec.add("val".into(), port).unwrap();
assert!(vec.set_from_str("val", "42").is_ok());
}
#[test]
fn set_from_str_missing_port() {
let mut vec = PortVec::default();
assert_eq!(
vec.set_from_str("missing", "42"),
Err(crate::error::Error::NotFound { name: "missing".into() })
);
}
#[test]
fn iter_empty_yields_nothing() {
let vec = PortVec::default();
assert_eq!(vec.iter().count(), 0);
}
#[test]
fn iter_yields_all_entries_in_insertion_order() {
let mut vec = PortVec::default();
vec.add("a".into(), crate::PortVariant::create_inbound(1i32))
.unwrap();
vec.add("b".into(), crate::PortVariant::create_outbound(2i32))
.unwrap();
vec.add("c".into(), crate::PortVariant::create_inoutbound(3i32))
.unwrap();
let names: Vec<&str> = vec.iter().map(|(n, _)| n).collect();
assert_eq!(names, ["a", "b", "c"]);
assert_eq!(vec.iter().count(), 3);
}
#[test]
fn iter_yields_matching_port_refs() {
let mut vec = PortVec::default();
vec.add("x".into(), crate::PortVariant::create_inbound(42i32))
.unwrap();
let (name, port) = vec.iter().next().unwrap();
assert_eq!(name, "x");
assert_eq!(port.get::<i32>().unwrap(), Some(42));
}
#[test]
fn iter_mut_empty_yields_nothing() {
let mut vec = PortVec::default();
assert_eq!(vec.iter_mut().count(), 0);
}
#[test]
fn iter_mut_yields_all_entries_in_insertion_order() {
let mut vec = PortVec::default();
vec.add("a".into(), crate::PortVariant::create_inbound(1i32))
.unwrap();
vec.add("b".into(), crate::PortVariant::create_outbound(2i32))
.unwrap();
vec.add("c".into(), crate::PortVariant::create_inoutbound(3i32))
.unwrap();
let names: Vec<&str> = vec.iter_mut().map(|(n, _)| n).collect();
assert_eq!(names, ["a", "b", "c"]);
assert_eq!(vec.iter_mut().count(), 3);
}
#[test]
fn iter_mut_allows_mutation_of_port_values() {
let mut vec = PortVec::default();
vec.add("a".into(), crate::PortVariant::create_inoutbound(1i32))
.unwrap();
vec.add("b".into(), crate::PortVariant::create_inoutbound(2i32))
.unwrap();
for (_, port) in vec.iter_mut() {
let current = port.get::<i32>().unwrap().unwrap();
port.set(current * 10).unwrap();
}
assert_eq!(vec.get::<i32>("a"), Ok(10));
assert_eq!(vec.get::<i32>("b"), Ok(20));
}
#[test]
fn iter_mut_yields_matching_port_refs() {
let mut vec = PortVec::default();
vec.add("x".into(), crate::PortVariant::create_inoutbound(42i32))
.unwrap();
{
let (name, port) = vec.iter_mut().next().unwrap();
assert_eq!(name, "x");
port.set(99i32).unwrap();
}
assert_eq!(vec.get::<i32>("x"), Ok(99));
}
}