#![allow(clippy::doc_markdown)] #![allow(clippy::must_use_candidate)] #![allow(clippy::too_many_lines)]
pub use crate::core::error::{QuantRS2Error, QuantRS2Result};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ErrorCategory {
Core,
Circuit,
Simulation,
Hardware,
Algorithm,
Annealing,
Symbolic,
Runtime,
Unknown,
}
impl ErrorCategory {
pub const fn name(&self) -> &'static str {
match self {
Self::Core => "Core",
Self::Circuit => "Circuit",
Self::Simulation => "Simulation",
Self::Hardware => "Hardware",
Self::Algorithm => "Algorithm",
Self::Annealing => "Annealing",
Self::Symbolic => "Symbolic",
Self::Runtime => "Runtime",
Self::Unknown => "Unknown",
}
}
pub const fn description(&self) -> &'static str {
match self {
Self::Core => "Errors from core quantum operations (gates, qubits, registers)",
Self::Circuit => "Errors from circuit construction and manipulation",
Self::Simulation => "Errors from quantum simulation backends",
Self::Hardware => "Errors from quantum hardware integration",
Self::Algorithm => "Errors from quantum algorithms and machine learning",
Self::Annealing => "Errors from quantum annealing operations",
Self::Symbolic => "Errors from symbolic computation",
Self::Runtime => "Runtime errors (I/O, serialization, network, etc.)",
Self::Unknown => "Uncategorized or unknown errors",
}
}
}
pub trait QuantRS2ErrorExt {
fn category(&self) -> ErrorCategory;
fn is_recoverable(&self) -> bool;
fn user_message(&self) -> String;
fn is_invalid_input(&self) -> bool;
fn is_resource_error(&self) -> bool;
}
impl QuantRS2ErrorExt for QuantRS2Error {
fn category(&self) -> ErrorCategory {
match self {
Self::InvalidQubitId(_)
| Self::InvalidGateOp(_)
| Self::LinalgError(_)
| Self::MatrixConstruction(_)
| Self::MatrixInversion(_)
| Self::InvalidInput(_)
| Self::InvalidParameter(_)
| Self::InvalidOperation(_)
| Self::UnsupportedOperation(_)
| Self::UnsupportedGate(_)
| Self::DivisionByZero => ErrorCategory::Core,
Self::CircuitValidationFailed(_)
| Self::RoutingError(_)
| Self::GateApplicationFailed(_)
| Self::GateFusionError(_)
| Self::CompilationTimeout(_) => ErrorCategory::Circuit,
Self::BackendExecutionFailed(_)
| Self::UnsupportedQubits(_, _)
| Self::TensorNetwork(_)
| Self::ComputationError(_)
| Self::QuantumDecoherence(_)
| Self::StateNotFound(_) => ErrorCategory::Simulation,
Self::NetworkError(_)
| Self::NoHardwareAvailable(_)
| Self::CalibrationNotFound(_)
| Self::HardwareTargetNotFound(_)
| Self::NodeNotFound(_)
| Self::NodeUnavailable(_)
| Self::QKDFailure(_) => ErrorCategory::Hardware,
Self::OptimizationFailed(_) => ErrorCategory::Algorithm,
Self::RuntimeError(_)
| Self::ExecutionError(_)
| Self::NoStorageAvailable(_)
| Self::StorageCapacityExceeded(_)
| Self::AccessDenied(_)
| Self::LockPoisoned(_)
| Self::IndexOutOfBounds { .. } => ErrorCategory::Runtime,
}
}
fn is_recoverable(&self) -> bool {
match self {
Self::NetworkError(_)
| Self::NodeUnavailable(_)
| Self::NoHardwareAvailable(_)
| Self::BackendExecutionFailed(_) => true,
_ => false,
}
}
fn user_message(&self) -> String {
match self {
Self::InvalidQubitId(id) => format!("Qubit {id} is not valid for this operation"),
Self::UnsupportedOperation(op) => {
format!("Operation '{op}' is not supported")
}
Self::UnsupportedQubits(count, msg) => {
format!("Cannot handle {count} qubits: {msg}")
}
Self::NetworkError(msg) => {
format!("Network connection failed: {msg}. Please check your internet connection and try again.")
}
Self::NoHardwareAvailable(msg) => {
format!(
"No quantum hardware is currently available: {msg}. Please try again later."
)
}
Self::OptimizationFailed(msg) => {
format!("Optimization did not converge: {msg}. Try adjusting parameters.")
}
Self::BackendExecutionFailed(msg) => {
format!("Simulation failed: {msg}. This might be a temporary issue.")
}
_ => format!("{self}"),
}
}
fn is_invalid_input(&self) -> bool {
matches!(
self,
Self::InvalidInput(_)
| Self::InvalidParameter(_)
| Self::InvalidQubitId(_)
| Self::InvalidOperation(_)
| Self::InvalidGateOp(_)
)
}
fn is_resource_error(&self) -> bool {
matches!(
self,
Self::NoStorageAvailable(_)
| Self::StorageCapacityExceeded(_)
| Self::NoHardwareAvailable(_)
| Self::UnsupportedQubits(_, _)
)
}
}
#[must_use]
pub fn with_context(error: QuantRS2Error, context: &str) -> QuantRS2Error {
match error {
QuantRS2Error::InvalidQubitId(id) => {
QuantRS2Error::InvalidQubitId(id) }
QuantRS2Error::DivisionByZero => QuantRS2Error::DivisionByZero,
QuantRS2Error::UnsupportedOperation(msg) => {
QuantRS2Error::UnsupportedOperation(format!("{context}: {msg}"))
}
QuantRS2Error::GateApplicationFailed(msg) => {
QuantRS2Error::GateApplicationFailed(format!("{context}: {msg}"))
}
QuantRS2Error::CircuitValidationFailed(msg) => {
QuantRS2Error::CircuitValidationFailed(format!("{context}: {msg}"))
}
QuantRS2Error::BackendExecutionFailed(msg) => {
QuantRS2Error::BackendExecutionFailed(format!("{context}: {msg}"))
}
QuantRS2Error::UnsupportedQubits(count, msg) => {
QuantRS2Error::UnsupportedQubits(count, format!("{context}: {msg}"))
}
QuantRS2Error::InvalidInput(msg) => {
QuantRS2Error::InvalidInput(format!("{context}: {msg}"))
}
QuantRS2Error::ComputationError(msg) => {
QuantRS2Error::ComputationError(format!("{context}: {msg}"))
}
QuantRS2Error::LinalgError(msg) => QuantRS2Error::LinalgError(format!("{context}: {msg}")),
QuantRS2Error::RoutingError(msg) => {
QuantRS2Error::RoutingError(format!("{context}: {msg}"))
}
QuantRS2Error::MatrixConstruction(msg) => {
QuantRS2Error::MatrixConstruction(format!("{context}: {msg}"))
}
QuantRS2Error::MatrixInversion(msg) => {
QuantRS2Error::MatrixInversion(format!("{context}: {msg}"))
}
QuantRS2Error::OptimizationFailed(msg) => {
QuantRS2Error::OptimizationFailed(format!("{context}: {msg}"))
}
QuantRS2Error::TensorNetwork(msg) => {
QuantRS2Error::TensorNetwork(format!("{context}: {msg}"))
}
QuantRS2Error::RuntimeError(msg) => {
QuantRS2Error::RuntimeError(format!("{context}: {msg}"))
}
QuantRS2Error::ExecutionError(msg) => {
QuantRS2Error::ExecutionError(format!("{context}: {msg}"))
}
QuantRS2Error::InvalidGateOp(msg) => {
QuantRS2Error::InvalidGateOp(format!("{context}: {msg}"))
}
QuantRS2Error::InvalidParameter(msg) => {
QuantRS2Error::InvalidParameter(format!("{context}: {msg}"))
}
QuantRS2Error::QuantumDecoherence(msg) => {
QuantRS2Error::QuantumDecoherence(format!("{context}: {msg}"))
}
QuantRS2Error::NoStorageAvailable(msg) => {
QuantRS2Error::NoStorageAvailable(format!("{context}: {msg}"))
}
QuantRS2Error::CalibrationNotFound(msg) => {
QuantRS2Error::CalibrationNotFound(format!("{context}: {msg}"))
}
QuantRS2Error::AccessDenied(msg) => {
QuantRS2Error::AccessDenied(format!("{context}: {msg}"))
}
QuantRS2Error::StorageCapacityExceeded(msg) => {
QuantRS2Error::StorageCapacityExceeded(format!("{context}: {msg}"))
}
QuantRS2Error::HardwareTargetNotFound(msg) => {
QuantRS2Error::HardwareTargetNotFound(format!("{context}: {msg}"))
}
QuantRS2Error::GateFusionError(msg) => {
QuantRS2Error::GateFusionError(format!("{context}: {msg}"))
}
QuantRS2Error::UnsupportedGate(msg) => {
QuantRS2Error::UnsupportedGate(format!("{context}: {msg}"))
}
QuantRS2Error::CompilationTimeout(msg) => {
QuantRS2Error::CompilationTimeout(format!("{context}: {msg}"))
}
QuantRS2Error::NodeNotFound(msg) => {
QuantRS2Error::NodeNotFound(format!("{context}: {msg}"))
}
QuantRS2Error::NodeUnavailable(msg) => {
QuantRS2Error::NodeUnavailable(format!("{context}: {msg}"))
}
QuantRS2Error::NetworkError(msg) => {
QuantRS2Error::NetworkError(format!("{context}: {msg}"))
}
QuantRS2Error::NoHardwareAvailable(msg) => {
QuantRS2Error::NoHardwareAvailable(format!("{context}: {msg}"))
}
QuantRS2Error::StateNotFound(msg) => {
QuantRS2Error::StateNotFound(format!("{context}: {msg}"))
}
QuantRS2Error::InvalidOperation(msg) => {
QuantRS2Error::InvalidOperation(format!("{context}: {msg}"))
}
QuantRS2Error::QKDFailure(msg) => QuantRS2Error::QKDFailure(format!("{context}: {msg}")),
QuantRS2Error::LockPoisoned(msg) => {
QuantRS2Error::LockPoisoned(format!("{context}: {msg}"))
}
QuantRS2Error::IndexOutOfBounds { index, len } => {
QuantRS2Error::IndexOutOfBounds { index, len } }
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_category() {
let error = QuantRS2Error::InvalidQubitId(5);
assert_eq!(error.category(), ErrorCategory::Core);
let error = QuantRS2Error::CircuitValidationFailed("test".into());
assert_eq!(error.category(), ErrorCategory::Circuit);
let error = QuantRS2Error::NetworkError("connection failed".into());
assert_eq!(error.category(), ErrorCategory::Hardware);
}
#[test]
fn test_is_recoverable() {
let error = QuantRS2Error::NetworkError("timeout".into());
assert!(error.is_recoverable());
let error = QuantRS2Error::InvalidQubitId(5);
assert!(!error.is_recoverable());
}
#[test]
fn test_is_invalid_input() {
let error = QuantRS2Error::InvalidInput("bad value".into());
assert!(error.is_invalid_input());
let error = QuantRS2Error::NetworkError("timeout".into());
assert!(!error.is_invalid_input());
}
#[test]
fn test_with_context() {
let error = QuantRS2Error::InvalidInput("bad parameter".into());
let contextualized = with_context(error, "in circuit builder");
match contextualized {
QuantRS2Error::InvalidInput(msg) => {
assert!(msg.contains("in circuit builder"));
assert!(msg.contains("bad parameter"));
}
_ => panic!("Expected InvalidInput variant"),
}
}
#[test]
fn test_user_message() {
let error = QuantRS2Error::InvalidQubitId(42);
let msg = error.user_message();
assert!(msg.contains("42"));
assert!(msg.contains("not valid"));
}
#[test]
fn test_category_name_and_description() {
assert_eq!(ErrorCategory::Core.name(), "Core");
assert!(ErrorCategory::Circuit.description().contains("circuit"));
assert!(ErrorCategory::Hardware.description().contains("hardware"));
}
}