use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DataEnum, DeriveInput, Fields, Ident};
pub fn dispatch_struct_enum_single_qubit(input: DeriveInput) -> TokenStream {
let ident = input.ident;
match input.data {
Data::Struct(_ds) => operate_single_qubit_struct(ident),
Data::Enum(de) => operate_single_qubit_enum(de, ident),
_ => panic!("OperateSingleQubit can only be derived on structs and enums"),
}
}
fn operate_single_qubit_enum(de: DataEnum, ident: Ident) -> TokenStream {
let DataEnum { variants, .. } = de;
let match_quotes = variants.into_iter().map(|v| {
let vident = v.ident.clone();
let fields = match v.fields {
Fields::Unnamed(fields) => fields,
_ => panic!(
"OperateSingleQubit can only be derived for enums with newtype structs as variants"
),
};
if fields.unnamed.iter().len() != 1 {
panic!(
"OperateSingleQubit can only be derived for enums with newtype structs as variants"
)
}
quote! {
&#ident::#vident(ref inner) => {OperateSingleQubit::qubit(&(*inner))},
}
});
quote! {
#[automatically_derived]
impl OperateSingleQubit for #ident{
fn qubit(&self) -> &usize {
match self{
#(#match_quotes)*
_ => panic!("Unexpectedly cannot match variant")
}
}
}
}
}
fn operate_single_qubit_struct(ident: Ident) -> TokenStream {
quote! {
#[automatically_derived]
impl OperateSingleQubit for #ident{
fn qubit(&self ) -> &usize {
&self.qubit
}
}
}
}
pub fn dispatch_struct_enum_two_qubit(input: DeriveInput) -> TokenStream {
let ident = input.ident;
match input.data {
Data::Struct(_ds) => operate_two_qubit_struct(ident),
Data::Enum(de) => operate_two_qubit_enum(de, ident),
_ => panic!("OperateTwoQubit can only be derived on structs and enums"),
}
}
fn operate_two_qubit_enum(de: DataEnum, ident: Ident) -> TokenStream {
let DataEnum { variants, .. } = de;
let control_quotes = variants.clone().into_iter().map(|v| {
let vident = v.ident.clone();
let fields = match v.fields {
Fields::Unnamed(fields) => fields,
_ => panic!(
"OperateSingleQubit can only be derived for enums with newtype structs as variants"
),
};
if fields.unnamed.iter().len() != 1 {
panic!(
"OperateSingleQubit can only be derived for enums with newtype structs as variants"
)
}
quote! {
&#ident::#vident(ref inner) => {OperateTwoQubit::control(&(*inner))},
}
});
let target_quotes = variants.into_iter().map(|v| {
let vident = v.ident.clone();
let fields = match v.fields {
Fields::Unnamed(fields) => fields,
_ => panic!(
"OperateSingleQubit can only be derived for enums with newtype structs as variants"
),
};
if fields.unnamed.iter().len() != 1 {
panic!(
"OperateSingleQubit can only be derived for enums with newtype structs as variants"
)
}
quote! {
&#ident::#vident(ref inner) => {OperateTwoQubit::target(&(*inner))},
}
});
quote! {
#[automatically_derived]
impl OperateTwoQubit for #ident{
fn control(&self) -> &usize {
match self{
#(#control_quotes)*
_ => panic!("Unexpectedly cannot match variant")
}
}
fn target(&self) -> &usize {
match self{
#(#target_quotes)*
_ => panic!("Unexpectedly cannot match variant")
}
}
}
}
}
fn operate_two_qubit_struct(ident: Ident) -> TokenStream {
quote! {
#[automatically_derived]
impl OperateTwoQubit for #ident{
fn control(&self ) -> &usize {
&self.control
}
fn target(&self ) -> &usize {
&self.target
}
}
}
}
pub fn dispatch_struct_enum_three_qubit(input: DeriveInput) -> TokenStream {
let ident = input.ident;
match input.data {
Data::Struct(_ds) => operate_three_qubit_struct(ident),
Data::Enum(de) => operate_three_qubit_enum(de, ident),
_ => panic!("OperateThreeQubit can only be derived on structs and enums"),
}
}
fn operate_three_qubit_enum(de: DataEnum, ident: Ident) -> TokenStream {
let DataEnum { variants, .. } = de;
let control_0_quotes = variants.clone().into_iter().map(|v| {
let vident = v.ident.clone();
let fields = match v.fields {
Fields::Unnamed(fields) => fields,
_ => panic!(
"OperateSingleQubit can only be derived for enums with newtype structs as variants"
),
};
if fields.unnamed.iter().len() != 1 {
panic!(
"OperateSingleQubit can only be derived for enums with newtype structs as variants"
)
}
quote! {
&#ident::#vident(ref inner) => {OperateThreeQubit::control_0(&(*inner))},
}
});
let control_1_quotes = variants.clone().into_iter().map(|v| {
let vident = v.ident.clone();
let fields = match v.fields {
Fields::Unnamed(fields) => fields,
_ => panic!(
"OperateSingleQubit can only be derived for enums with newtype structs as variants"
),
};
if fields.unnamed.iter().len() != 1 {
panic!(
"OperateSingleQubit can only be derived for enums with newtype structs as variants"
)
}
quote! {
&#ident::#vident(ref inner) => {OperateThreeQubit::control_1(&(*inner))},
}
});
let target_quotes = variants.into_iter().map(|v| {
let vident = v.ident.clone();
let fields = match v.fields {
Fields::Unnamed(fields) => fields,
_ => panic!(
"OperateSingleQubit can only be derived for enums with newtype structs as variants"
),
};
if fields.unnamed.iter().len() != 1 {
panic!(
"OperateSingleQubit can only be derived for enums with newtype structs as variants"
)
}
quote! {
&#ident::#vident(ref inner) => {OperateThreeQubit::target(&(*inner))},
}
});
quote! {
#[automatically_derived]
impl OperateThreeQubit for #ident{
fn control_0(&self) -> &usize {
match self{
#(#control_0_quotes)*
_ => panic!("Unexpectedly cannot match variant")
}
}
fn control_1(&self) -> &usize {
match self{
#(#control_1_quotes)*
_ => panic!("Unexpectedly cannot match variant")
}
}
fn target(&self) -> &usize {
match self{
#(#target_quotes)*
_ => panic!("Unexpectedly cannot match variant")
}
}
}
}
}
fn operate_three_qubit_struct(ident: Ident) -> TokenStream {
quote! {
#[automatically_derived]
impl OperateThreeQubit for #ident{
fn control_0(&self ) -> &usize {
&self.control_0
}
fn control_1(&self ) -> &usize {
&self.control_1
}
fn target(&self ) -> &usize {
&self.target
}
}
}
}
pub fn dispatch_struct_enum_multi_qubit(input: DeriveInput) -> TokenStream {
let ident = input.ident;
match input.data {
Data::Struct(_ds) => operate_multi_qubit_struct(ident),
Data::Enum(de) => operate_multi_qubit_enum(de, ident),
_ => panic!("OperateSingleQubit can only be derived on structs and enums"),
}
}
fn operate_multi_qubit_enum(de: DataEnum, ident: Ident) -> TokenStream {
let DataEnum { variants, .. } = de;
let match_quotes = variants.into_iter().map(|v| {
let vident = v.ident.clone();
let fields = match v.fields {
Fields::Unnamed(fields) => fields,
_ => panic!(
"OperateMultiQubit can only be derived for enums with newtype structs as variants"
),
};
if fields.unnamed.iter().len() != 1 {
panic!(
"OperateMultiQubit can only be derived for enums with newtype structs as variants"
)
}
quote! {
&#ident::#vident(ref inner) => {OperateMultiQubit::qubits(&(*inner))},
}
});
quote! {
#[automatically_derived]
impl OperateMultiQubit for #ident{
fn qubits(&self) -> &Vec<usize> {
match self{
#(#match_quotes)*
_ => panic!("Unexpectedly cannot match variant")
}
}
}
}
}
fn operate_multi_qubit_struct(ident: Ident) -> TokenStream {
quote! {
#[automatically_derived]
impl OperateMultiQubit for #ident{
fn qubits(&self ) -> &Vec<usize> {
&self.qubits
}
}
}
}