• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Qiskit / qiskit / 19082828935

04 Nov 2025 09:06PM UTC coverage: 88.178% (-0.009%) from 88.187%
19082828935

Pull #15208

github

web-flow
Merge 2824c324c into 56db921d1
Pull Request #15208: Add ways to iterate over the `Target` in C.

102 of 126 new or added lines in 2 files covered. (80.95%)

989 existing lines in 42 files now uncovered.

93963 of 106561 relevant lines covered (88.18%)

1143131.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.68
/crates/circuit/src/classical/expr/binary.rs
1
// This code is part of Qiskit.
2
//
3
// (C) Copyright IBM 2025
4
//
5
// This code is licensed under the Apache License, Version 2.0. You may
6
// obtain a copy of this license in the LICENSE.txt file in the root directory
7
// of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8
//
9
// Any modifications or derivative works of this code must retain this
10
// copyright notice, and modified files need to carry a notice indicating
11
// that they have been altered from the originals.
12

13
use crate::classical::expr::{Expr, ExprKind, PyExpr};
14
use crate::classical::types::Type;
15
use crate::imports;
16
use pyo3::prelude::*;
17
use pyo3::types::PyTuple;
18
use pyo3::{IntoPyObjectExt, intern};
19

20
/// A binary expression.
21
#[derive(Clone, Debug, PartialEq)]
22
pub struct Binary {
23
    pub op: BinaryOp,
24
    pub left: Expr,
25
    pub right: Expr,
26
    pub ty: Type,
27
    pub constant: bool,
28
}
29

30
/// The Rust-side enum indicating a [Binary] expression's kind.
31
///
32
/// The values are part of the public Qiskit Python interface, since
33
/// they are public in the sister Python enum `_BinaryOp` in `expr.py`
34
/// and used in our QPY serialization format.
35
///
36
/// WARNING: If you add more, **be sure to update expr.py** as well
37
/// as the implementation of [::bytemuck::CheckedBitPattern]
38
/// below.
39
#[repr(u8)]
40
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
41
pub enum BinaryOp {
42
    BitAnd = 1,
43
    BitOr = 2,
44
    BitXor = 3,
45
    LogicAnd = 4,
46
    LogicOr = 5,
47
    Equal = 6,
48
    NotEqual = 7,
49
    Less = 8,
50
    LessEqual = 9,
51
    Greater = 10,
52
    GreaterEqual = 11,
53
    ShiftLeft = 12,
54
    ShiftRight = 13,
55
    Add = 14,
56
    Sub = 15,
57
    Mul = 16,
58
    Div = 17,
59
}
60

61
unsafe impl ::bytemuck::CheckedBitPattern for BinaryOp {
62
    type Bits = u8;
63

64
    fn is_valid_bit_pattern(bits: &Self::Bits) -> bool {
3,252✔
65
        *bits > 0 && *bits < 18
3,252✔
66
    }
3,252✔
67
}
68

69
impl<'py> IntoPyObject<'py> for Binary {
70
    type Target = PyAny;
71
    type Output = Bound<'py, PyAny>;
72
    type Error = PyErr;
73

74
    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
2,274✔
75
        Ok(Bound::new(py, (PyBinary(self), PyExpr(ExprKind::Binary)))?.into_any())
2,274✔
76
    }
2,274✔
77
}
78

79
impl<'a, 'py> FromPyObject<'a, 'py> for Binary {
80
    type Error = <PyBinary as FromPyObject<'a, 'py>>::Error;
81

82
    fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
3,212✔
83
        let PyBinary(b) = ob.extract()?;
3,212✔
84
        Ok(b)
3,212✔
85
    }
3,212✔
86
}
87

88
impl<'py> IntoPyObject<'py> for BinaryOp {
89
    type Target = PyAny;
90
    type Output = Bound<'py, Self::Target>;
91
    type Error = PyErr;
92

93
    fn into_pyobject(self, py: Python<'py>) -> Result<Self::Output, Self::Error> {
2,552✔
94
        imports::BINARY_OP.get_bound(py).call1((self as usize,))
2,552✔
95
    }
2,552✔
96
}
97

98
impl<'a, 'py> FromPyObject<'a, 'py> for BinaryOp {
99
    type Error = PyErr;
100

101
    fn extract(ob: Borrowed<'a, 'py, PyAny>) -> Result<Self, Self::Error> {
3,252✔
102
        let value = ob.getattr(intern!(ob.py(), "value"))?;
3,252✔
103
        Ok(bytemuck::checked::cast(value.extract::<u8>()?))
3,252✔
104
    }
3,252✔
105
}
106

107
/// A Python descriptor to prevent PyO3 from attempting to import the Python-side
108
/// enum before we're initialized.
109
#[pyclass(module = "qiskit._accelerate.circuit.classical.expr")]
110
struct PyBinaryOp;
111

112
#[pymethods]
113
impl PyBinaryOp {
114
    fn __get__(&self, obj: &Bound<PyAny>, _obj_type: &Bound<PyAny>) -> Py<PyAny> {
3,340✔
115
        imports::BINARY_OP.get_bound(obj.py()).clone().unbind()
3,340✔
116
    }
3,340✔
117
}
118

119
/// A binary expression.
120
///
121
/// Args:
122
///     op: The opcode describing which operation is being done.
123
///     left: The left-hand operand.
124
///     right: The right-hand operand.
125
///     type: The resolved type of the result.
126
#[pyclass(eq, extends = PyExpr, name = "Binary", module = "qiskit._accelerate.circuit.classical.expr")]
127
#[derive(PartialEq, Clone, Debug)]
128
pub struct PyBinary(Binary);
129

UNCOV
130
#[pymethods]
×
131
impl PyBinary {
132
    // The docstring for 'Op' is defined in Python (expr.py).
133
    #[classattr]
134
    #[allow(non_snake_case)]
135
    fn Op(py: Python) -> PyResult<Py<PyAny>> {
12✔
136
        PyBinaryOp.into_py_any(py)
12✔
137
    }
12✔
138

139
    #[new]
140
    #[pyo3(text_signature = "(op, left, right, type)")]
141
    fn new(py: Python, op: BinaryOp, left: Expr, right: Expr, ty: Type) -> PyResult<Py<Self>> {
3,252✔
142
        let constant = left.is_const() && right.is_const();
3,252✔
143
        Py::new(
3,252✔
144
            py,
3,252✔
145
            (
3,252✔
146
                PyBinary(Binary {
3,252✔
147
                    op,
3,252✔
148
                    left,
3,252✔
149
                    right,
3,252✔
150
                    ty,
3,252✔
151
                    constant,
3,252✔
152
                }),
3,252✔
153
                PyExpr(ExprKind::Binary),
3,252✔
154
            ),
3,252✔
155
        )
156
    }
3,252✔
157

158
    #[getter]
159
    fn get_op(&self, py: Python) -> PyResult<Py<PyAny>> {
2,552✔
160
        self.0.op.into_py_any(py)
2,552✔
161
    }
2,552✔
162

163
    #[getter]
164
    fn get_left(&self, py: Python) -> PyResult<Py<PyAny>> {
4,300✔
165
        self.0.left.clone().into_py_any(py)
4,300✔
166
    }
4,300✔
167

168
    #[getter]
169
    fn get_right(&self, py: Python) -> PyResult<Py<PyAny>> {
4,144✔
170
        self.0.right.clone().into_py_any(py)
4,144✔
171
    }
4,144✔
172

173
    #[getter]
174
    fn get_const(&self) -> bool {
442✔
175
        self.0.constant
442✔
176
    }
442✔
177

178
    #[getter]
179
    fn get_type(&self, py: Python) -> PyResult<Py<PyAny>> {
6,790✔
180
        self.0.ty.into_py_any(py)
6,790✔
181
    }
6,790✔
182

183
    fn accept<'py>(
3,286✔
184
        slf: PyRef<'py, Self>,
3,286✔
185
        visitor: &Bound<'py, PyAny>,
3,286✔
186
    ) -> PyResult<Bound<'py, PyAny>> {
3,286✔
187
        visitor.call_method1(intern!(visitor.py(), "visit_binary"), (slf,))
3,286✔
188
    }
3,286✔
189

190
    fn __reduce__<'py>(&self, py: Python<'py>) -> PyResult<Bound<'py, PyTuple>> {
542✔
191
        (
192
            py.get_type::<Self>(),
542✔
193
            (
194
                self.get_op(py)?,
542✔
195
                self.get_left(py)?,
542✔
196
                self.get_right(py)?,
542✔
197
                self.get_type(py)?,
542✔
198
            ),
199
        )
200
            .into_pyobject(py)
542✔
201
    }
542✔
202

203
    fn __repr__(&self, py: Python) -> PyResult<String> {
8✔
204
        Ok(format!(
8✔
205
            "Binary({}, {}, {}, {})",
8✔
206
            self.get_op(py)?.bind(py).repr()?,
8✔
207
            self.get_left(py)?.bind(py).repr()?,
8✔
208
            self.get_right(py)?.bind(py).repr()?,
8✔
209
            self.get_type(py)?.bind(py).repr()?,
8✔
210
        ))
211
    }
8✔
212
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc