dataport 0.1.0

Port abstractions for data types
Documentation
// Copyright © 2025 Stephan Kunz

#![no_std]
#![doc = include_str!("../README.md")]

#[cfg(doctest)]
doc_comment::doctest!("../README.md");

extern crate alloc;

// re-export macros
pub use dataport_macros::{
	create_inbound_entry, create_inbound_entry_parseable, create_inoutbound_entry, create_inoutbound_entry_parseable,
	create_outbound_entry, create_outbound_entry_parseable, create_port_array, create_port_map, create_port_vec,
};

// define Arc, Mutex, RwLock & Guards
pub type Arc<T> = portable_atomic_util::Arc<T>;
#[allow(unused)]
pub type Mutex<T> = spin::Mutex<T>;
pub type RwLock<T> = spin::RwLock<T>;
pub type RwLockReadGuard<'a, T> = spin::RwLockReadGuard<'a, T>;
pub type RwLockWriteGuard<'a, T> = spin::RwLockWriteGuard<'a, T>;

// flatten
pub use any_port_value::AnyPortValue;
pub use bind::{
	BindCommons, BindIn, BindInOut, BindOut,
	bound_value::{BoundValueReadGuard, BoundValueWriteGuard},
	in_::InBound,
	in_out::InOutBound,
	out_::OutBound,
};
pub use collections::{
	EMPTY_PORT_ARRAY, EmptyPortArray, PortCollection, PortCollectionAccessors, PortCollectionAccessorsCommon,
	PortCollectionMut, PortCollectionProvider, PortCollectionProviderMut, PortList, port_array::PortArray,
	port_map::PortMap, port_vec::PortVec,
};
pub use error::Error;
pub use port_variant::PortVariant;

// internal module structure
mod any_port_value;
mod bind;
mod collections;
mod error;
mod port_variant;
pub mod prelude;

/// An immutable thread safe `String` type
/// see: [Logan Smith](https://www.youtube.com/watch?v=A4cKi7PTJSs).
type ConstString = Arc<str>;

pub trait PortCommons {
	/// Binds this port to the port 'variant'.
	/// # Errors
	/// - [`Error::DataType`], if 'self' is not the same type 'T' as 'variant'.
	/// - [`Error::PortType`], if 'variant' is not a valid port type.
	fn use_from_variant(&mut self, variant: &PortVariant) -> Result<(), Error>;

	/// Binds this port to the port 'name' of 'collection'.
	/// # Errors
	/// - [`Error::DataType`], if 'self' is not the same type 'T' as 'name' in 'collection'.
	/// - [`Error::OtherNotFound`], if 'collection' does not contains port 'name'.
	/// - [`Error::PortType`], if 'variant' is not a valid port type.
	fn use_from_collection(&mut self, name: &str, collection: &dyn PortCollection) -> Result<(), Error>;
}

/// Checks whether the given name is a pointer into a port [`collection`](crate::collections).
#[must_use]
pub fn is_port_collection_pointer(name: &str) -> bool {
	(name.starts_with('{') && name.ends_with('}') && is_valid_port_name(&name[1..name.len() - 1])) || name == "{=}"
}

/// Returns `true` if a name is a valid port name, otherwise `false`.
/// Valid port names
/// - starts with an 'Alphabetic' character and
/// - contains only 'Alphabetic' or 'Numeric' characters '_' and ' '.
#[must_use]
pub fn is_valid_port_name(name: &str) -> bool {
	if name.is_empty() {
		false
	} else {
		let mut iter = name.chars();
		// check first digit beeing alphabetic
		if let Some(c) = iter.next()
			&& !c.is_alphabetic()
		{
			return false;
		}

		// check the rest for allowed chars
		for c in iter {
			if !c.is_alphanumeric() && c != '_' && c != ' ' {
				return false;
			}
		}

		true
	}
}