dataport 0.1.0

Port abstractions for data types
Documentation
// Copyright © 2026 Stephan Kunz
//! An extendable unsorted collection of ports.

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,
};

/// An extendable unsorted list of [`PortVariant`]s.
#[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>() {}

	// check, that the auto traits are available.
	#[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));
	}
}