Skip to main content

quil/instruction/
control_flow.rs

1use quil_rs::instruction::{
2    Jump, JumpUnless, JumpWhen, Label, MemoryReference, Target, TargetPlaceholder,
3};
4use rigetti_pyo3::{
5    impl_compare, impl_hash, impl_repr, py_wrap_data_struct, py_wrap_type, py_wrap_union_enum,
6    pyo3::{pymethods, types::PyString, Py},
7    PyWrapper,
8};
9
10use crate::{impl_eq, impl_pickle_for_instruction, impl_to_quil, instruction::PyMemoryReference};
11
12/// Implements __copy__ and __deepcopy__ for instructions containing a [`Target`].
13///
14/// __copy__ implements a shallow copy by returning a reference to the object.
15///
16/// __deepcopy__ performs a deep copy by cloning the Rust reference, and replacing
17/// any [`TargetPlaceholder`]s from the original intruction with new instances so
18/// that resolving placeholders on the copy does not affect the original.
19macro_rules! impl_copy_for_target_containing_instructions {
20    ($name: ident) => {
21        #[pyo3::pymethods]
22        impl $name {
23            pub fn __copy__(&self) -> Self {
24                self.clone()
25            }
26
27            pub fn __deepcopy__(&self, _memo: &pyo3::types::PyDict) -> Self {
28                use quil_rs::instruction::{Target, TargetPlaceholder};
29                let mut copy = rigetti_pyo3::PyWrapper::into_inner(self.clone());
30                if let Target::Placeholder(placeholder) = copy.target {
31                    copy.target = Target::Placeholder(TargetPlaceholder::new(
32                        placeholder.as_inner().to_string(),
33                    ))
34                }
35
36                Self(copy)
37            }
38        }
39    };
40}
41
42py_wrap_data_struct! {
43    #[derive(Debug, Hash, PartialEq, Eq)]
44    #[pyo3(subclass, module = "quil.instructions")]
45    PyLabel(Label) as "Label" {
46        target: Target => PyTarget
47    }
48}
49impl_repr!(PyLabel);
50impl_hash!(PyLabel);
51impl_to_quil!(PyLabel);
52impl_copy_for_target_containing_instructions!(PyLabel);
53impl_eq!(PyLabel);
54impl_pickle_for_instruction!(PyLabel);
55
56#[pymethods]
57impl PyLabel {
58    #[new]
59    fn new(target: PyTarget) -> Self {
60        PyLabel(Label::new(target.into_inner()))
61    }
62}
63
64py_wrap_union_enum! {
65    #[derive(Debug, Hash, PartialEq, Eq)]
66    PyTarget(Target) as "Target" {
67        fixed: Fixed => Py<PyString>,
68        placeholder: Placeholder => PyTargetPlaceholder
69    }
70}
71impl_repr!(PyTarget);
72impl_hash!(PyTarget);
73impl_to_quil!(PyTarget);
74impl_eq!(PyTarget);
75
76py_wrap_type! {
77    #[pyo3(subclass)]
78    #[derive(Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
79    PyTargetPlaceholder(TargetPlaceholder) as "TargetPlaceholder"
80}
81impl_repr!(PyTargetPlaceholder);
82impl_hash!(PyTargetPlaceholder);
83impl_compare!(PyTargetPlaceholder);
84
85#[pymethods]
86impl PyTargetPlaceholder {
87    #[new]
88    pub fn new(base_label: String) -> Self {
89        Self(TargetPlaceholder::new(base_label))
90    }
91
92    #[getter]
93    pub fn base_label(&self) -> &str {
94        PyWrapper::as_inner(self).as_inner()
95    }
96}
97
98py_wrap_data_struct! {
99    #[derive(Debug, PartialEq)]
100    #[pyo3(subclass, module = "quil.instructions")]
101    PyJump(Jump) as "Jump" {
102        target: Target => PyTarget
103    }
104}
105impl_repr!(PyJump);
106impl_to_quil!(PyJump);
107impl_copy_for_target_containing_instructions!(PyJump);
108impl_eq!(PyJump);
109impl_pickle_for_instruction!(PyJump);
110
111#[pymethods]
112impl PyJump {
113    #[new]
114    fn new(target: PyTarget) -> Self {
115        Self(Jump::new(target.into_inner()))
116    }
117}
118
119py_wrap_data_struct! {
120    #[derive(Debug, PartialEq)]
121    #[pyo3(subclass, module = "quil.instructions")]
122    PyJumpWhen(JumpWhen) as "JumpWhen" {
123        target: Target => PyTarget,
124        condition: MemoryReference => PyMemoryReference
125    }
126}
127impl_repr!(PyJumpWhen);
128impl_to_quil!(PyJumpWhen);
129impl_copy_for_target_containing_instructions!(PyJumpWhen);
130impl_eq!(PyJumpWhen);
131impl_pickle_for_instruction!(PyJumpWhen);
132
133#[pymethods]
134impl PyJumpWhen {
135    #[new]
136    fn new(target: PyTarget, condition: PyMemoryReference) -> Self {
137        Self(JumpWhen::new(target.into_inner(), condition.into_inner()))
138    }
139}
140
141py_wrap_data_struct! {
142    #[derive(Debug, PartialEq)]
143    #[pyo3(subclass, module = "quil.instructions")]
144    PyJumpUnless(JumpUnless) as "JumpUnless" {
145        target: Target => PyTarget,
146        condition: MemoryReference => PyMemoryReference
147    }
148}
149impl_repr!(PyJumpUnless);
150impl_to_quil!(PyJumpUnless);
151impl_copy_for_target_containing_instructions!(PyJumpUnless);
152impl_eq!(PyJumpUnless);
153impl_pickle_for_instruction!(PyJumpUnless);
154
155#[pymethods]
156impl PyJumpUnless {
157    #[new]
158    fn new(target: PyTarget, condition: PyMemoryReference) -> Self {
159        Self(JumpUnless::new(target.into_inner(), condition.into_inner()))
160    }
161}