1#[macro_export]
8macro_rules! instance_select {
9 ($Select:ident: $Base:path: $Class:ty { $( $Enum:ident($Param:ident = $Instance:ty) ),+ $(,)? }) => {
10 pub enum $Select<
11 $( $Param:
12 $crate::Pack +
13 $crate::Instance<$Class> +
14 $Base
15 = $Instance
16 ),+
17 > {
18 $( $Enum($Param), )+
19 }
20
21 impl $Select {
22 #[allow(unused_assignments)]
23 fn index(&self) -> u32 {
24 let mut i = 0;
25 $(
26 if let $Select::$Enum(_) = self {
27 return i;
28 }
29 i += 1;
30 )+
31 unreachable!()
32 }
33
34 #[allow(unused_assignments)]
35 fn method_source(method: &str) -> String {
36 use $crate::class::*;
37 let cpref = format!(
38 "{}_{}",
39 <$Class>::name(),
40 method,
41 ).to_uppercase();
42
43 let mut cases = Vec::new();
44 let mut i = 0;
45 $(
46 let inst_name = <$Instance as $crate::Instance<$Class>>::inst_name();
47 cases.push([
48 format!("\tif (sel_idx == {}) {{", i),
49 format!(
50 "\t\treturn {}_{}({}_ARGS_B(1, 0));",
51 inst_name, method, cpref,
52 ),
53 "\t}".to_string(),
54 ].join("\n"));
55 i += 1;
56 )+
57 let cases_text = cases.join(" else\n");
58 [
59 &format!(
60 "{}_RET {}_{}({}_ARGS_DEF) {{",
61 cpref, Self::inst_name(), method, cpref,
62 ),
63 "\tint sel_idx = ibuf[0];",
64 &cases_text,
65 &format!("\treturn {}_RET_BAD;", cpref),
66 "}",
67 ].join("\n")
68 }
69 }
70
71 impl $crate::Instance<$Class> for $Select {
72 fn source(cache: &mut std::collections::HashSet<u64>) -> String {
73 use $crate::{TypeHash, class::*};
74 if !cache.insert(Self::type_hash()) {
75 return String::new()
76 }
77 let mut ms = Vec::new();
78 for method in <$Class>::methods().into_iter() {
79 ms.push(Self::method_source(&method));
80 }
81 [
82 $( <$Instance as $crate::Instance<$Class>>::source(cache), )+
83 ms.join("\n"),
84 ].join("\n")
85 }
86
87 fn inst_name() -> String {
88 use $crate::TypeHash;
89 format!("__select_{:x}", Self::type_hash())
90 }
91 }
92
93 impl $crate::Pack for $Select {
94 fn size_int() -> usize {
95 let sizes = [
96 $( <$Instance>::size_int(), )+
97 ];
98 1 + *sizes.iter().max().unwrap()
99 }
100 fn size_float() -> usize {
101 let sizes = [
102 $( <$Instance>::size_float(), )+
103 ];
104 *sizes.iter().max().unwrap()
105 }
106 fn pack_to(&self, mut buffer_int: &mut [i32], buffer_float: &mut [f32]) {
107 use $crate::pack::*;
108 self.index().pack_int_to(buffer_int);
109 buffer_int = &mut buffer_int[1..];
110 match self {
111 $( $Select::$Enum(x) => x.pack_to(buffer_int, buffer_float), )+
112 }
113 }
114 }
115
116 $(
117 impl From<$Instance> for $Select {
118 fn from(origin: $Instance) -> Self {
119 $Select::$Enum(origin)
120 }
121 }
122 )+
123 };
124}
125
126#[cfg(test)]
127mod check {
128 use crate::{
129 shape::{
130 Shape, ShapeClass,
131 test::TestShape,
132 },
133 instance_select,
134 };
135
136 instance_select!(
137 TestSelect: Shape: ShapeClass {
138 Shape1(T1 = TestShape<i32>),
139 Shape2(T2 = TestShape<f32>),
140 }
141 );
142}