dataport-macros 0.1.0

Macros for dataport
Documentation
// Copyright © 2025 Stephan Kunz
//! Macros for port and port collection creation.

#[doc(hidden)]
extern crate proc_macro;

mod implementation;

use proc_macro::TokenStream;
use quote::{ToTokens, quote};
use syn::parse_macro_input;

use crate::implementation::{Params, PortVariant, quote_from_input, quote_from_type, quote_from_value};

/// Creates an array of ports.
/// # Usage:
/// port_array!(<comma_separated_list_of_name/port_pairs>)
///
/// Best to use with port generation macros:
/// port_array!(
///     inbound!(<name>, <type>, <value>),
///     outbound!(<name>, <type>),
///     inoutbound!(<name>. <value>)
/// )
#[proc_macro]
pub fn create_port_array(input: TokenStream) -> TokenStream {
	let output: proc_macro2::TokenStream = input.into();
	quote! {
		dataport::PortArray::from_array([#output])
	}
	.into()
}

/// Creates a list of ports.
/// # Usage:
/// port_list!(<comma_separated_list_of_name/port_pairs>)
///
/// Best to use with port generation macros:
/// port_list!(
///     inoutbound!(<name>, <type>, <value>),
///     inbound!(<name>, <type>),
///     outbound!(<name>. <value>)
/// )
#[proc_macro]
pub fn create_port_vec(input: TokenStream) -> TokenStream {
	let output: proc_macro2::TokenStream = input.into();
	quote! {
		dataport::PortVec::from_array([#output])
	}
	.into()
}

/// Creates a map of ports.
/// # Usage:
/// port_map!(<comma_separated_list_of_name/port_pairs>)
///
/// Best to use with port generation macros:
/// port_map!(
///     outbound!(<name>, <type>, <value>),
///     inoutbound!(<name>, <type>),
///     inbound!(<name>. <value>)
/// )
#[proc_macro]
pub fn create_port_map(input: TokenStream) -> TokenStream {
	let output: proc_macro2::TokenStream = input.into();
	quote! {
		dataport::PortMap::from_array([#output])
	}
	.into()
}

/// Creates a name/inbound_port pair.
/// # Usages:
/// inbound!(name, type)
/// inbound!(name, value)
/// inbound!(name, type, value)
#[proc_macro]
pub fn create_inbound_entry(input: TokenStream) -> TokenStream {
	let params = parse_macro_input!(input as Params);

	let name = params.port_name;
	if let Some(value) = params.port_value {
		if let Some(tp) = params.port_type {
			quote_from_input(name, tp, value, params.collection, PortVariant::InBound, false).into()
		} else {
			quote_from_value(PortVariant::InBound, name, value.to_token_stream(), false).into()
		}
	} else if let Some(tp) = params.port_type {
		quote_from_type(PortVariant::InBound, name, tp, false).into()
	} else {
		panic!("missing type or value as parameter")
	}
}

/// Creates a name/inbound_port pair with a parseable data type.
/// # Usages:
/// inbound!(name, type)
/// inbound!(name, value)
/// inbound!(name, type, value)
#[proc_macro]
pub fn create_inbound_entry_parseable(input: TokenStream) -> TokenStream {
	let params = parse_macro_input!(input as Params);

	let name = params.port_name;
	if let Some(value) = params.port_value {
		if let Some(tp) = params.port_type {
			quote_from_input(name, tp, value, params.collection, PortVariant::InBound, true).into()
		} else {
			quote_from_value(PortVariant::InBound, name, value.to_token_stream(), true).into()
		}
	} else if let Some(tp) = params.port_type {
		quote_from_type(PortVariant::InBound, name, tp, true).into()
	} else {
		panic!("missing type or value as parameter")
	}
}

/// Creates a name/inoutbound_port pair.
/// # Usages:
/// inoutbound!(name, type)
/// inoutbound!(name, value)
/// inoutbound!(name, type, value)
#[proc_macro]
pub fn create_inoutbound_entry(input: TokenStream) -> TokenStream {
	let params = parse_macro_input!(input as Params);

	let name = params.port_name;
	if let Some(value) = params.port_value {
		if let Some(tp) = params.port_type {
			quote_from_input(name, tp, value, params.collection, PortVariant::InOutBound, false).into()
		} else {
			quote_from_value(PortVariant::InOutBound, name, value.to_token_stream(), false).into()
		}
	} else if let Some(tp) = params.port_type {
		quote_from_type(PortVariant::InOutBound, name, tp, false).into()
	} else {
		panic!("missing type or value as parameter")
	}
}

/// Creates a name/inoutbound_port pair with a parseable data type.
/// # Usages:
/// inoutbound!(name, type)
/// inoutbound!(name, value)
/// inoutbound!(name, type, value)
#[proc_macro]
pub fn create_inoutbound_entry_parseable(input: TokenStream) -> TokenStream {
	let params = parse_macro_input!(input as Params);

	let name = params.port_name;
	if let Some(value) = params.port_value {
		if let Some(tp) = params.port_type {
			quote_from_input(name, tp, value, params.collection, PortVariant::InOutBound, true).into()
		} else {
			quote_from_value(PortVariant::InOutBound, name, value.to_token_stream(), true).into()
		}
	} else if let Some(tp) = params.port_type {
		quote_from_type(PortVariant::InOutBound, name, tp, true).into()
	} else {
		panic!("missing type or value as parameter")
	}
}

/// Creates a name/outbound_port pair.
/// # Usages:
/// outbound!(name, type)
/// outbound!(name, value)
/// outbound!(name, type, value)
#[proc_macro]
pub fn create_outbound_entry(input: TokenStream) -> TokenStream {
	let params = parse_macro_input!(input as Params);

	let name = params.port_name;
	if let Some(value) = params.port_value {
		if let Some(tp) = params.port_type {
			quote_from_input(name, tp, value, params.collection, PortVariant::OutBound, false).into()
		} else {
			quote_from_value(PortVariant::OutBound, name, value.to_token_stream(), false).into()
		}
	} else if let Some(tp) = params.port_type {
		quote_from_type(PortVariant::OutBound, name, tp, false).into()
	} else {
		panic!("missing type or value as parameter")
	}
}
/// Creates a name/outbound_port pair with a parseable data type.
/// # Usages:
/// outbound!(name, type)
/// outbound!(name, value)
/// outbound!(name, type, value)
#[proc_macro]
pub fn create_outbound_entry_parseable(input: TokenStream) -> TokenStream {
	let params = parse_macro_input!(input as Params);

	let name = params.port_name;
	if let Some(value) = params.port_value {
		if let Some(tp) = params.port_type {
			quote_from_input(name, tp, value, params.collection, PortVariant::OutBound, true).into()
		} else {
			quote_from_value(PortVariant::OutBound, name, value.to_token_stream(), true).into()
		}
	} else if let Some(tp) = params.port_type {
		quote_from_type(PortVariant::OutBound, name, tp, true).into()
	} else {
		panic!("missing type or value as parameter")
	}
}