Skip to main content

dataport/collections/
port_vec.rs

1// Copyright © 2026 Stephan Kunz
2//! An extendable unsorted collection of ports.
3
4use core::ops::{Deref, DerefMut};
5
6use alloc::{boxed::Box, vec::Vec};
7
8use crate::{
9	ConstString,
10	any_port_value::AnyPortValue,
11	bind::{
12		BindCommons,
13		bound_value::{BoundValueReadGuard, BoundValueWriteGuard},
14	},
15	collections::{PortCollection, PortCollectionAccessors, PortCollectionAccessorsCommon, PortCollectionMut},
16	error::Error,
17	port_variant::PortVariant,
18};
19
20/// An extendable unsorted list of [`PortVariant`]s.
21#[derive(Clone, Debug, Default)]
22#[repr(transparent)]
23pub struct PortVec(Vec<(ConstString, PortVariant)>);
24
25impl PortVec {
26	pub fn with_capacity(size: usize) -> Self {
27		Self(Vec::with_capacity(size))
28	}
29
30	pub fn from_array<const N: usize>(array: [(ConstString, PortVariant); N]) -> Self {
31		Self(Vec::from(array))
32	}
33
34	pub fn inner(&self) -> &Vec<(ConstString, PortVariant)> {
35		&self.0
36	}
37
38	pub fn inner_mut(&mut self) -> &mut Vec<(ConstString, PortVariant)> {
39		&mut self.0
40	}
41}
42
43impl Deref for PortVec {
44	type Target = Vec<(ConstString, PortVariant)>;
45
46	fn deref(&self) -> &Self::Target {
47		&self.0
48	}
49}
50
51impl DerefMut for PortVec {
52	fn deref_mut(&mut self) -> &mut Self::Target {
53		&mut self.0
54	}
55}
56
57impl PortCollection for PortVec {
58	fn find(&self, name: &str) -> Option<&PortVariant> {
59		self.0
60			.iter()
61			.find(|port| &*port.0 == name)
62			.map(|v| &v.1 as _)
63	}
64
65	fn find_mut(&mut self, name: &str) -> Option<&mut PortVariant> {
66		self.0
67			.iter_mut()
68			.find(|port| &*port.0 == name)
69			.map(|v| &mut v.1 as _)
70	}
71
72	fn set_from_str(&mut self, name: &str, value: &str) -> Result<(), Error> {
73		if let Some(port) = self.find_mut(name) {
74			port.set_from_str(value)
75		} else {
76			Err(Error::NotFound { name: name.into() })
77		}
78	}
79
80	fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (&'a str, &'a PortVariant)> + 'a> {
81		Box::new(self.0.iter().map(|(name, port)| (&**name, port)))
82	}
83
84	fn iter_mut<'a>(&'a mut self) -> Box<dyn Iterator<Item = (&'a str, &'a mut PortVariant)> + 'a> {
85		Box::new(
86			self.0
87				.iter_mut()
88				.map(|(name, port)| (&**name, port)),
89		)
90	}
91}
92
93impl PortCollectionMut for PortVec {
94	fn add(&mut self, name: ConstString, port: PortVariant) -> Result<(), Error> {
95		if self.find(&name).is_some() {
96			Err(Error::AlreadyExists)
97		} else {
98			self.0.push((name, port));
99			Ok(())
100		}
101	}
102
103	fn delete(&mut self, name: &str) -> Result<PortVariant, Error> {
104		let name = name.into();
105		if let Some(index) = self.0.iter().position(|r| r.0 == name) {
106			Ok(self.0.remove(index).1)
107		} else {
108			Err(Error::NotFound { name })
109		}
110	}
111}
112
113impl PortCollectionAccessorsCommon for PortVec {
114	fn contains_name(&self, name: &str) -> bool {
115		self.find(name).is_some()
116	}
117
118	fn give_to_bound(&self, name: &str, bound: &mut dyn BindCommons) -> Result<(), Error> {
119		self.find(name)
120			.map_or(Err(Error::NotFound { name: name.into() }), |port| {
121				bound.use_from_variant(port)
122			})
123	}
124
125	fn give_to_collection(
126		&self,
127		name: &str,
128		other_collection: &mut dyn PortCollection,
129		other_name: &str,
130	) -> Result<(), Error> {
131		self.find(name)
132			.map_or(Err(Error::NotFound { name: name.into() }), |port| {
133				other_collection
134					.find_mut(other_name)
135					.map_or(Err(Error::OtherNotFound { name: other_name.into() }), |variant| {
136						variant.use_from_variant(port)
137					})
138			})
139	}
140
141	fn give_to_variant(&self, name: &str, variant: &mut PortVariant) -> Result<(), Error> {
142		self.find(name)
143			.map_or(Err(Error::NotFound { name: name.into() }), |port| {
144				variant.use_from_variant(port)
145			})
146	}
147
148	fn sequence_number(&self, name: &str) -> Result<u32, Error> {
149		if let Some(port) = self.find(name) {
150			Ok(port.sequence_number())
151		} else {
152			Err(Error::NotFound { name: name.into() })
153		}
154	}
155
156	fn use_from_bound(&mut self, name: &str, bound: &dyn BindCommons) -> Result<(), Error> {
157		self.find_mut(name)
158			.map_or(Err(Error::NotFound { name: name.into() }), |port| port.use_from_bound(bound))
159	}
160
161	fn use_from_collection(
162		&mut self,
163		name: &str,
164		other_collection: &dyn PortCollection,
165		other_name: &str,
166	) -> Result<(), Error> {
167		other_collection
168			.find(other_name)
169			.map_or(Err(Error::OtherNotFound { name: other_name.into() }), |other| {
170				self.use_from_variant(name, other)
171			})
172	}
173
174	fn use_from_variant(&mut self, name: &str, variant: &PortVariant) -> Result<(), Error> {
175		if let Some(self_port) = self.find_mut(name) {
176			self_port.use_from_variant(variant)
177		} else {
178			Err(Error::NotFound { name: name.into() })
179		}
180	}
181}
182
183impl PortCollectionAccessors for PortVec {
184	fn contains<T: AnyPortValue>(&self, name: &str) -> Result<bool, Error> {
185		if let Some(p) = self.find(name) {
186			if p.is::<T>() { Ok(true) } else { Err(Error::DataType) }
187		} else {
188			Ok(false)
189		}
190	}
191
192	fn get<T>(&self, name: &str) -> Result<T, Error>
193	where
194		T: AnyPortValue + Clone,
195	{
196		if let Some(port) = self.find(name) {
197			match port.get::<T>()? {
198				Some(t) => Ok(t),
199				None => Err(Error::NoValueSet),
200			}
201		} else {
202			Err(Error::NotFound { name: name.into() })
203		}
204	}
205
206	fn read<T: AnyPortValue>(&self, name: &str) -> Result<BoundValueReadGuard<T>, Error> {
207		if let Some(port) = self.find(name) {
208			port.read()
209		} else {
210			Err(Error::NotFound { name: name.into() })
211		}
212	}
213
214	fn try_read<T: AnyPortValue>(&self, name: &str) -> Result<BoundValueReadGuard<T>, Error> {
215		if let Some(port) = self.find(name) {
216			port.try_read()
217		} else {
218			Err(Error::NotFound { name: name.into() })
219		}
220	}
221
222	fn replace<T: AnyPortValue>(&mut self, name: &str, value: T) -> Result<Option<T>, Error> {
223		if let Some(port) = self.find_mut(name) {
224			port.replace(value)
225		} else {
226			Err(Error::NotFound { name: name.into() })
227		}
228	}
229
230	fn set<T: AnyPortValue>(&mut self, name: &str, value: T) -> Result<(), Error> {
231		if let Some(port) = self.find_mut(name) {
232			port.set(value)
233		} else {
234			Err(Error::NotFound { name: name.into() })
235		}
236	}
237
238	fn take<T: AnyPortValue>(&mut self, name: &str) -> Result<Option<T>, Error> {
239		if let Some(port) = self.find_mut(name) {
240			port.take()
241		} else {
242			Err(Error::NotFound { name: name.into() })
243		}
244	}
245
246	fn write<T: AnyPortValue>(&mut self, name: &str) -> Result<BoundValueWriteGuard<T>, Error> {
247		if let Some(port) = self.find_mut(name) {
248			port.write()
249		} else {
250			Err(Error::NotFound { name: name.into() })
251		}
252	}
253
254	fn try_write<T: AnyPortValue>(&mut self, name: &str) -> Result<BoundValueWriteGuard<T>, Error> {
255		if let Some(port) = self.find_mut(name) {
256			port.try_write()
257		} else {
258			Err(Error::NotFound { name: name.into() })
259		}
260	}
261}
262
263#[cfg(test)]
264mod tests {
265	use super::*;
266
267	const fn is_normal<T: Sized + Send + Sync>() {}
268
269	// check, that the auto traits are available.
270	#[test]
271	const fn normal_types() {
272		is_normal::<&PortVec>();
273		is_normal::<PortVec>();
274	}
275
276	#[test]
277	fn insert_duplicate_name_returns_already_exists() {
278		let mut vec = PortVec::default();
279		let port = crate::PortVariant::create_outbound(42i32);
280		assert!(vec.add("dup".into(), port).is_ok());
281
282		let port2 = crate::PortVariant::create_inbound(0i32);
283		assert_eq!(vec.add("dup".into(), port2), Err(crate::error::Error::AlreadyExists));
284	}
285
286	#[test]
287	fn set_from_str_existing_port() {
288		let mut vec = PortVec::default();
289		let port = crate::PortVariant::create_outbound_parseable(0i32);
290		vec.add("val".into(), port).unwrap();
291		assert!(vec.set_from_str("val", "42").is_ok());
292	}
293
294	#[test]
295	fn set_from_str_missing_port() {
296		let mut vec = PortVec::default();
297		assert_eq!(
298			vec.set_from_str("missing", "42"),
299			Err(crate::error::Error::NotFound { name: "missing".into() })
300		);
301	}
302
303	#[test]
304	fn iter_empty_yields_nothing() {
305		let vec = PortVec::default();
306		assert_eq!(vec.iter().count(), 0);
307	}
308
309	#[test]
310	fn iter_yields_all_entries_in_insertion_order() {
311		let mut vec = PortVec::default();
312		vec.add("a".into(), crate::PortVariant::create_inbound(1i32))
313			.unwrap();
314		vec.add("b".into(), crate::PortVariant::create_outbound(2i32))
315			.unwrap();
316		vec.add("c".into(), crate::PortVariant::create_inoutbound(3i32))
317			.unwrap();
318
319		let names: Vec<&str> = vec.iter().map(|(n, _)| n).collect();
320		assert_eq!(names, ["a", "b", "c"]);
321		assert_eq!(vec.iter().count(), 3);
322	}
323
324	#[test]
325	fn iter_yields_matching_port_refs() {
326		let mut vec = PortVec::default();
327		vec.add("x".into(), crate::PortVariant::create_inbound(42i32))
328			.unwrap();
329		let (name, port) = vec.iter().next().unwrap();
330		assert_eq!(name, "x");
331		assert_eq!(port.get::<i32>().unwrap(), Some(42));
332	}
333
334	#[test]
335	fn iter_mut_empty_yields_nothing() {
336		let mut vec = PortVec::default();
337		assert_eq!(vec.iter_mut().count(), 0);
338	}
339
340	#[test]
341	fn iter_mut_yields_all_entries_in_insertion_order() {
342		let mut vec = PortVec::default();
343		vec.add("a".into(), crate::PortVariant::create_inbound(1i32))
344			.unwrap();
345		vec.add("b".into(), crate::PortVariant::create_outbound(2i32))
346			.unwrap();
347		vec.add("c".into(), crate::PortVariant::create_inoutbound(3i32))
348			.unwrap();
349
350		let names: Vec<&str> = vec.iter_mut().map(|(n, _)| n).collect();
351		assert_eq!(names, ["a", "b", "c"]);
352		assert_eq!(vec.iter_mut().count(), 3);
353	}
354
355	#[test]
356	fn iter_mut_allows_mutation_of_port_values() {
357		let mut vec = PortVec::default();
358		vec.add("a".into(), crate::PortVariant::create_inoutbound(1i32))
359			.unwrap();
360		vec.add("b".into(), crate::PortVariant::create_inoutbound(2i32))
361			.unwrap();
362		for (_, port) in vec.iter_mut() {
363			let current = port.get::<i32>().unwrap().unwrap();
364			port.set(current * 10).unwrap();
365		}
366		assert_eq!(vec.get::<i32>("a"), Ok(10));
367		assert_eq!(vec.get::<i32>("b"), Ok(20));
368	}
369
370	#[test]
371	fn iter_mut_yields_matching_port_refs() {
372		let mut vec = PortVec::default();
373		vec.add("x".into(), crate::PortVariant::create_inoutbound(42i32))
374			.unwrap();
375		{
376			let (name, port) = vec.iter_mut().next().unwrap();
377			assert_eq!(name, "x");
378			port.set(99i32).unwrap();
379		}
380		assert_eq!(vec.get::<i32>("x"), Ok(99));
381	}
382}