1use std::collections::HashSet;
5use std::convert::TryFrom;
6use std::fmt::Debug;
7
8pub trait StructureIdentifier: Copy + Clone + Debug + TryFrom<isize> + Into<isize> {
10 fn known_variants() -> &'static [Self];
12
13 fn allowed_values(no_catchall: bool) -> Option<HashSet<isize>>;
18
19 fn as_str(&self) -> Option<&'static str>;
21}
22
23#[macro_export]
37macro_rules! structure_mapping {
38 ( $id:ident $(, $val:literal = $name:ident $desc:expr )* $(,)?) => {
39 #[derive(Copy, Clone, Debug)]
40 #[allow(missing_docs)]
41 pub enum $id {
42 $( $name, )+
43 }
44
45 impl TryFrom<isize> for $id {
46 type Error = isize;
47
48 fn try_from(val: isize) -> Result<Self, Self::Error> {
49 match val {
50 $( $val => Ok(Self::$name), )*
51 value => Err(value),
52 }
53 }
54 }
55
56 impl From<$id> for isize {
57 fn from(val: $id) -> Self {
58 match val {
59 $( $id::$name => $val, )*
60 }
61 }
62 }
63
64 impl StructureIdentifier for $id {
65 fn known_variants() -> &'static [Self] {
66 &[
67 $( Self::$name, )*
68 ]
69 }
70
71 fn allowed_values(_no_catchall: bool) -> Option<HashSet<isize>> {
72 Some(vec![$( $val, )*].into_iter().collect())
73 }
74
75 fn as_str(&self) -> Option<&'static str> {
76 match self {
77 $( Self::$name => Some($desc), )*
78 }
79 }
80 }
81
82 };
83 ( $id:ident $(, $val:literal = $name:ident $desc:expr )*, $othername:ident $(,)?) => {
84 #[derive(Copy, Clone, Debug)]
85 #[allow(missing_docs)]
86 pub enum $id {
87 $( $name, )*
88 $othername(isize),
89 }
90
91 impl From<isize> for $id {
92 fn from(val: isize) -> Self {
93 match val {
94 $( $val => Self::$name, )*
95 x => Self::$othername(x),
96 }
97 }
98 }
99
100 impl From<$id> for isize {
101 fn from(val: $id) -> Self {
102 match val {
103 $( $id::$name => $val, )*
104 $id::$othername(x) => x,
105 }
106 }
107 }
108
109 impl StructureIdentifier for $id {
110 fn known_variants() -> &'static [Self] {
111 &[
112 $( Self::$name, )*
113 ]
114 }
115
116 fn allowed_values(no_catchall: bool) -> Option<HashSet<isize>> {
117 if no_catchall {
118 Some(vec![$( $val, )*].into_iter().collect())
119 } else {
120 None
121 }
122 }
123
124 fn as_str(&self) -> Option<&'static str> {
125 match self {
126 $( Self::$name => Some($desc), )*
127 Self::$othername(_) => None,
128 }
129 }
130 }
131
132 };
133}
134
135#[macro_export]
140macro_rules! neuromorpho_ext {
141 ( $id:ident $(, $val:literal = $name:ident $desc:expr )* $(,)?) => {
142 structure_mapping!(
143 $id,
144 -1 = Root "root",
145 0 = Undefined "undefined",
146 1 = Soma "soma",
147 2 = Axon "axon",
148 3 = BasalDendrite "basal dendrite",
149 4 = ApicalDendrite "apical dendrite",
150 $($val = $name $desc, )*
151 );
152 };
153 ( $id:ident $(, $val:literal = $name:ident $desc:expr )*, $othername:ident $(,)?) => {
154 structure_mapping!(
155 $id,
156 -1 = Root "root",
157 0 = Undefined "undefined",
158 1 = Soma "soma",
159 2 = Axon "axon",
160 3 = BasalDendrite "basal dendrite",
161 4 = ApicalDendrite "apical dendrite",
162 $($val = $name $desc, )*
163 $othername,
164 );
165 };
166}
167
168neuromorpho_ext!(NeuromorphoStructure, Custom);
169neuromorpho_ext!(CnicStructure, 5 = ForkPoint "fork point", 6 = EndPoint "end point", 7 = Custom "custom");
170neuromorpho_ext!(
171 NavisStructure,
172 5 = ForkPoint "fork point",
173 6 = EndPoint "end point",
174 7 = Presynapse "presynapse",
175 8 = Postsynapse "postsynapse",
176 9 = PreAndPostsynapse "pre and postsynapse",
177 Custom,
178);
179neuromorpho_ext!(VnedStructure, 10 = SomaRelated "soma related", Custom);
180
181structure_mapping!(GulyasStructure, IsoDiameterStructure);
182structure_mapping!(AnyStructure, Any);