use std::fmt;
use crate::qubit::{ClassicalBit, QubitId};
#[derive(Clone, PartialEq, Eq, Debug)]
#[non_exhaustive]
pub enum Error {
QubitOutOfRange {
qubit: QubitId,
num_qubits: usize,
},
ClassicalBitOutOfRange {
bit: ClassicalBit,
num_classical: usize,
},
DuplicateQubit {
qubit: QubitId,
},
DimensionMismatch {
len: usize,
expected: usize,
},
NonClifford {
gate: &'static str,
},
Qasm {
line: usize,
col: usize,
message: String,
},
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::QubitOutOfRange { qubit, num_qubits } => {
write!(
f,
"qubit {qubit} out of range for {num_qubits}-qubit register"
)
}
Self::ClassicalBitOutOfRange { bit, num_classical } => {
write!(
f,
"classical bit {bit} out of range for {num_classical}-bit register"
)
}
Self::DuplicateQubit { qubit } => {
write!(f, "qubit {qubit} used more than once in a single gate")
}
Self::DimensionMismatch { len, expected } => {
write!(f, "amplitude buffer has length {len}, expected {expected}")
}
Self::NonClifford { gate } => {
write!(
f,
"{gate} is not in the Clifford group; the stabilizer backend cannot simulate it"
)
}
Self::Qasm { line, col, message } => {
write!(f, "OpenQASM 3 error at {line}:{col}: {message}")
}
}
}
}
impl std::error::Error for Error {}
pub type Result<T> = std::result::Result<T, Error>;
#[cfg(test)]
mod tests {
use super::*;
use crate::qubit::{ClassicalBit, QubitId};
#[test]
fn qubit_out_of_range_message() {
let e = Error::QubitOutOfRange { qubit: QubitId(3), num_qubits: 2 };
assert_eq!(e.to_string(), "qubit q3 out of range for 2-qubit register");
}
#[test]
fn classical_bit_out_of_range_message() {
let e = Error::ClassicalBitOutOfRange { bit: ClassicalBit(5), num_classical: 3 };
assert_eq!(e.to_string(), "classical bit c5 out of range for 3-bit register");
}
#[test]
fn duplicate_qubit_message() {
let e = Error::DuplicateQubit { qubit: QubitId(1) };
assert_eq!(e.to_string(), "qubit q1 used more than once in a single gate");
}
#[test]
fn dimension_mismatch_message() {
let e = Error::DimensionMismatch { len: 3, expected: 4 };
assert_eq!(e.to_string(), "amplitude buffer has length 3, expected 4");
}
#[test]
fn non_clifford_message() {
let e = Error::NonClifford { gate: "T" };
assert!(e.to_string().contains("T"));
assert!(e.to_string().contains("Clifford"));
}
#[test]
fn qasm_error_message() {
let e = Error::Qasm { line: 5, col: 10, message: "unexpected token".into() };
assert_eq!(e.to_string(), "OpenQASM 3 error at 5:10: unexpected token");
}
#[test]
fn error_implements_std_error() {
let e: &dyn std::error::Error = &Error::NonClifford { gate: "Toffoli" };
assert!(e.source().is_none());
}
}