roqoqo_derive/
involve_qubits.rs1use crate::{extract_fields_with_types, extract_variants_with_types};
14use proc_macro2::TokenStream;
15use quote::quote;
16use syn::{Data, DataEnum, DataStruct, DeriveInput, Ident};
17
18pub fn dispatch_struct_enum(input: DeriveInput) -> TokenStream {
20 let ident = input.ident;
21 match input.data {
22 Data::Struct(ds) => involve_qubits_struct(ds, ident),
23 Data::Enum(de) => involve_qubits_enum(de, ident),
24 _ => panic!("InvolveQubits can only be derived on structs and enums"),
25 }
26}
27
28fn involve_qubits_enum(de: DataEnum, ident: Ident) -> TokenStream {
31 let variants_with_type = extract_variants_with_types(de).into_iter();
32 let match_quotes = variants_with_type.clone().map(|(vident, _, _)| {
33 quote! {
34 &#ident::#vident(ref inner) => {InvolveQubits::involved_qubits(&(*inner))},
35 }
36 });
37
38 let match_quotes_classical = variants_with_type.map(|(vident, _, _)| {
39 quote! {
40 &#ident::#vident(ref inner) => {InvolveQubits::involved_classical(&(*inner))},
41 }
42 });
43 quote! {
44 #[automatically_derived]
45 impl InvolveQubits for #ident{
47 fn involved_qubits(&self) -> InvolvedQubits {
48 match self{
49 #(#match_quotes)*
50 _ => panic!("Unexpectedly cannot match variant")
51 }
52 }
53
54 fn involved_classical(&self) -> InvolvedClassical {
55 match self{
56 #(#match_quotes_classical)*
57 _ => panic!("Unexpectedly cannot match variant")
58 }
59 }
60 }
61 }
62}
63
64fn involve_qubits_struct(ds: DataStruct, ident: Ident) -> TokenStream {
66 let fields_with_type = extract_fields_with_types(ds).into_iter();
69
70 let mut qubit: bool = false;
72 let mut control: bool = false;
73 let mut control_0: bool = false;
74 let mut control_1: bool = false;
75 let mut control_2: bool = false;
76 let mut target: bool = false;
77 let mut qubits: bool = false;
78
79 for (fid, type_string, _) in fields_with_type {
82 match fid.clone().to_string().as_str() {
84 "qubit" => {
85 if type_string == Some("usize".to_string()) {
86 qubit = true
87 } else {
88 panic!("Field qubit must have type usize")
89 }
90 }
91 "target" => {
92 if type_string == Some("usize".to_string()) {
93 target = true;
94 } else {
95 panic!("Field target must have type usize")
96 }
97 }
98 "control" => {
99 if type_string == Some("usize".to_string()) {
100 control = true;
101 } else {
102 panic!("Field control must have type usize")
103 }
104 }
105 "control_0" => {
106 if type_string == Some("usize".to_string()) {
107 control_0 = true;
108 } else {
109 panic!("Field control_0 must have type usize")
110 }
111 }
112 "control_1" => {
113 if type_string == Some("usize".to_string()) {
114 control_1 = true;
115 } else {
116 panic!("Field control_1 must have type usize")
117 }
118 }
119 "control_2" => {
120 if type_string == Some("usize".to_string()) {
121 control_2 = true;
122 } else {
123 panic!("Field control_2 must have type usize")
124 }
125 }
126 "qubits" => {
127 qubits = true;
128 }
129 _ => {}
130 };
131 }
132 if qubit {
133 if control || target || qubits {
134 panic!("When deriving InvolveQubits, qubit field is not compatible with control, target or qubits fields");
135 };
136 quote! {
138 #[automatically_derived]
140 impl InvolveQubits for #ident{
141 fn involved_qubits(&self ) -> InvolvedQubits {
143 let mut new_hash_set: std::collections::HashSet<usize> = std::collections::HashSet::new();
144 new_hash_set.insert(self.qubit);
145 InvolvedQubits::Set(new_hash_set)
146 }
147 }
148 }
149 } else if control_2 {
150 if !(control_0 && control_1 && target) {
151 panic!("When deriving InvolveQubits for a four-qubit operation control_0, control_1, control_2 and target have to be present");
152 };
153 quote! {
155 #[automatically_derived]
157 impl InvolveQubits for #ident{
158 fn involved_qubits(&self ) -> InvolvedQubits {
160 let mut new_hash_set: std::collections::HashSet<usize> = std::collections::HashSet::new();
161 new_hash_set.insert(self.control_0);
162 new_hash_set.insert(self.control_1);
163 new_hash_set.insert(self.control_2);
164 new_hash_set.insert(self.target);
165 InvolvedQubits::Set(new_hash_set)
166 }
167 }
168 }
169 } else if control_0 || control_1 {
170 if control {
171 panic!("When deriving InvolveQubits for a three-qubit operation, control field is not compatible with control_0 and control_1 fields");
172 }
173 if !(control_0 && control_1 && target) {
174 panic!("When deriving InvolveQubits for a three-qubit operation control_0, control_1 and target have to be present");
175 };
176 if qubits {
177 panic!("When deriving InvolveQubits for a three-qubit operation, control_0 and control_1 fields are not compatible with qubits fields");
178 };
179 quote! {
181 #[automatically_derived]
183 impl InvolveQubits for #ident{
184 fn involved_qubits(&self ) -> InvolvedQubits {
186 let mut new_hash_set: std::collections::HashSet<usize> = std::collections::HashSet::new();
187 new_hash_set.insert(self.control_0);
188 new_hash_set.insert(self.control_1);
189 new_hash_set.insert(self.target);
190 InvolvedQubits::Set(new_hash_set)
191 }
192 }
193 }
194 } else if target || control {
195 if !(control && target) {
196 panic!("When deriving InvolveQubits control and target fields have to both be present");
197 };
198 if qubits {
199 panic!("When deriving InvolveQubits, control and target fields are not compatible with qubits fields");
200 };
201 quote! {
203 #[automatically_derived]
205 impl InvolveQubits for #ident{
206 fn involved_qubits(&self ) -> InvolvedQubits {
208 let mut new_hash_set: std::collections::HashSet<usize> = std::collections::HashSet::new();
209 new_hash_set.insert(self.control);
210 new_hash_set.insert(self.target);
211 InvolvedQubits::Set(new_hash_set)
212 }
213 }
214 }
215 } else if qubits {
216 quote! {
218 #[automatically_derived]
220 impl InvolveQubits for #ident{
221 fn involved_qubits(&self ) -> InvolvedQubits {
223 let mut new_hash_set: std::collections::HashSet<usize> = std::collections::HashSet::new();
224 for qubit in self.qubits.iter(){
225 new_hash_set.insert(*qubit);
226 }
227 InvolvedQubits::Set(new_hash_set)
228 }
229 }
230 }
231 } else {
232 panic!("To derive InvolveQubits qubit or control or target or qubits fields need to be present in struct")
233 }
234}