use crate::genomic::cortical_area::descriptors::CorticalSubUnitIndex;
use crate::genomic::cortical_area::descriptors::CorticalUnitIndex;
use crate::genomic::cortical_area::io_cortical_area_configuration_flag::{
FrameChangeHandling, PercentageNeuronPositioning, PoseSchema,
};
use crate::genomic::cortical_area::{
CorticalAreaType, CorticalID, IOCorticalAreaConfigurationFlag,
};
use crate::genomic::sensory_cortical_unit::UnitTopology;
use crate::motor_cortical_units;
use paste;
use serde_json::{Map, Value};
use std::collections::HashMap;
use std::fmt::{Display, Formatter};
#[macro_export]
macro_rules! get_allowed_frame_change_handling_impl { () => {
None
};
($($allowed:ident),+) => {
Some(&[$(FrameChangeHandling::$allowed),+] as &'static [FrameChangeHandling])
};
}
macro_rules! define_motor_cortical_units_enum {
(
MotorCorticalUnit {
$(
$(#[doc = $doc:expr])?
$variant_name:ident => {
friendly_name: $friendly_name:expr,
accepted_wrapped_io_data_type: $accepted_wrapped_io_data_type:expr,
cortical_id_unit_reference: $cortical_id_unit_reference:expr,
number_cortical_areas: $number_cortical_areas:expr,
cortical_type_parameters: {
$($param_name:ident: $param_type:ty),* $(,)?
},
$(allowed_frame_change_handling: [$($allowed_frame:ident),* $(,)?],)? cortical_area_properties: {
$($cortical_sub_unit_index:tt => ($io_cortical_area_configuration_flag_expr:expr, relative_position: [$rel_x:expr, $rel_y:expr, $rel_z:expr], channel_dimensions_default: [$dim_default_x:expr, $dim_default_y:expr, $dim_default_z:expr], channel_dimensions_min: [$dim_min_x:expr, $dim_min_y:expr, $dim_min_z:expr], channel_dimensions_max: [$dim_max_x:expr, $dim_max_y:expr, $dim_max_z:expr])),* $(,)?
}
}
),* $(,)?
}
) => {
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy, serde::Deserialize, serde::Serialize)]
pub enum MotorCorticalUnit {
$(
$(#[doc = $doc])?
$variant_name,
)*
}
impl MotorCorticalUnit {
$(
paste::paste! {
#[doc = "Get cortical area types array for " $friendly_name "."]
pub const fn [<get_cortical_area_types_array_for_ $variant_name:snake _with_parameters >](
$($param_name: $param_type),*) -> [CorticalAreaType; $number_cortical_areas] {
$(let _ = &$param_name;)*
[
$(CorticalAreaType::BrainOutput($io_cortical_area_configuration_flag_expr)),*
]
}
#[doc = "Get cortical IDs array for " $friendly_name "."]
pub const fn [<get_cortical_ids_array_for_ $variant_name:snake _with_parameters >](
$($param_name: $param_type,)* cortical_unit_index: CorticalUnitIndex) -> [CorticalID; $number_cortical_areas] {
$(let _ = &$param_name;)*
let cortical_unit_identifier: [u8; 3] = $cortical_id_unit_reference;
[
$(
$io_cortical_area_configuration_flag_expr .as_io_cortical_id(false, cortical_unit_identifier, cortical_unit_index, CorticalSubUnitIndex::from($cortical_sub_unit_index))
),*
]
}
}
)*
pub const fn get_snake_case_name(&self) -> &'static str {
match self {
$(
MotorCorticalUnit::$variant_name => paste::paste!{ stringify!([<$variant_name:snake>]) },
)*
}
}
pub const fn get_accepted_wrapped_io_data_type(&self) -> &'static str {
match self {
$(
MotorCorticalUnit::$variant_name => stringify!($variant_name:snake),
)*
}
}
pub fn from_snake_case_name(name: &str) -> Option<MotorCorticalUnit> {
match name {
$(
paste::paste!{ stringify!([<$variant_name:snake>]) } => Some(MotorCorticalUnit::$variant_name),
)*
_ => None,
}
}
pub const fn list_all() -> &'static [MotorCorticalUnit] {
&[
$(
MotorCorticalUnit::$variant_name,
)*
]
}
pub const fn get_friendly_name(&self) -> &'static str {
match self {
$(
MotorCorticalUnit::$variant_name => $friendly_name,
)*
}
}
pub const fn get_cortical_id_unit_reference(&self) -> [u8; 3] {
match self {
$(
MotorCorticalUnit::$variant_name => $cortical_id_unit_reference,
)*
}
}
pub const fn get_number_cortical_areas(&self) -> usize {
match self {
$(
MotorCorticalUnit::$variant_name => $number_cortical_areas,
)*
}
}
pub fn get_unit_default_topology(&self) -> HashMap<CorticalSubUnitIndex, UnitTopology> {
match self {
$(
MotorCorticalUnit::$variant_name => {
let mut topology = HashMap::new();
$(
topology.insert(
CorticalSubUnitIndex::from($cortical_sub_unit_index),
UnitTopology {
relative_position: [$rel_x, $rel_y, $rel_z],
channel_dimensions_default: [$dim_default_x, $dim_default_y, $dim_default_z],
channel_dimensions_min: [$dim_min_x, $dim_min_y, $dim_min_z],
channel_dimensions_max: [$dim_max_x, $dim_max_y, $dim_max_z],
}
);
)*
topology
}
)*
}
}
pub fn get_allowed_frame_change_handling(&self) -> Option<&'static [FrameChangeHandling]> {
match self {
$(
MotorCorticalUnit::$variant_name => {
$crate::get_allowed_frame_change_handling_impl!($($($allowed_frame),*)?)
}
)*
}
}
pub fn get_cortical_id_vector_from_index_and_serde_io_configuration_flags(&self, cortical_unit_index: CorticalUnitIndex, map: Map<String, Value>) -> Result<Vec<CorticalID>, crate::FeagiDataError> {
match self {
$(
MotorCorticalUnit::$variant_name => {
paste::paste! {
let array = MotorCorticalUnit::[<get_cortical_ids_array_for_ $variant_name:snake _with_parameters >](
$($param_type::try_from_serde_map(&map)?,)*
cortical_unit_index);
return Ok(array.to_vec());
}
}
)*
}
}
}
impl Display for MotorCorticalUnit {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
$(
MotorCorticalUnit::$variant_name => write!(f, $friendly_name),
)*
}
}
}
};
}
motor_cortical_units!(define_motor_cortical_units_enum);
impl MotorCorticalUnit {
pub fn try_from_legacy_subtype(subtype: &str) -> Option<CorticalID> {
let subtype_bytes = subtype.as_bytes();
if subtype_bytes.len() != 3 {
return None;
}
let subtype_arr = [subtype_bytes[0], subtype_bytes[1], subtype_bytes[2]];
for unit in Self::list_all() {
if unit.get_cortical_id_unit_reference() == subtype_arr {
return Some(unit.get_default_cortical_id_for_group(CorticalUnitIndex::from(0u8)));
}
}
None
}
pub fn get_default_cortical_id_for_group(&self, group_index: CorticalUnitIndex) -> CorticalID {
use crate::genomic::cortical_area::io_cortical_area_configuration_flag::{
FrameChangeHandling, PercentageNeuronPositioning,
};
let fh = FrameChangeHandling::Absolute;
let pos = PercentageNeuronPositioning::Linear;
match self {
MotorCorticalUnit::RotaryMotor => {
Self::get_cortical_ids_array_for_rotary_motor_with_parameters(fh, pos, group_index)
[0]
}
MotorCorticalUnit::PositionalServo => {
Self::get_cortical_ids_array_for_positional_servo_with_parameters(
FrameChangeHandling::Absolute,
pos,
group_index,
)[0]
}
MotorCorticalUnit::Gaze => {
Self::get_cortical_ids_array_for_gaze_with_parameters(fh, pos, group_index)[0]
}
MotorCorticalUnit::MiscData => {
Self::get_cortical_ids_array_for_misc_data_with_parameters(fh, group_index)[0]
}
MotorCorticalUnit::TextEnglishOutput => {
Self::get_cortical_ids_array_for_text_english_output_with_parameters(
fh,
group_index,
)[0]
}
MotorCorticalUnit::CountOutput => {
Self::get_cortical_ids_array_for_count_output_with_parameters(fh, pos, group_index)
[0]
}
MotorCorticalUnit::ObjectSegmentation => {
Self::get_cortical_ids_array_for_object_segmentation_with_parameters(
fh,
group_index,
)[0]
}
MotorCorticalUnit::SimpleVisionOutput => {
Self::get_cortical_ids_array_for_simple_vision_output_with_parameters(
fh,
group_index,
)[0]
}
MotorCorticalUnit::PoseEstimation => {
Self::get_cortical_ids_array_for_pose_estimation_with_parameters(
fh,
PoseSchema::HumanBody,
group_index,
)[0]
}
MotorCorticalUnit::DynamicImageProcessing => {
Self::get_cortical_ids_array_for_dynamic_image_processing_with_parameters(
fh,
pos,
group_index,
)[0]
}
MotorCorticalUnit::SpatialPointer => {
Self::get_cortical_ids_array_for_spatial_pointer_with_parameters(
fh,
pos,
group_index,
)[0]
}
}
}
}