use thiserror::Error;
#[derive(Debug, Error, Clone, PartialEq)]
#[non_exhaustive]
pub enum PrismError {
#[error("parse error at line {line}: {message}")]
Parse { line: usize, message: String },
#[error("unsupported construct at line {line}: `{construct}`{}", loop_hint(.construct))]
UnsupportedConstruct { construct: String, line: usize },
#[error("invalid qubit index {index} (register size: {register_size})")]
InvalidQubit { index: usize, register_size: usize },
#[error("invalid classical bit index {index} (register size: {register_size})")]
InvalidClassicalBit { index: usize, register_size: usize },
#[error("gate `{gate}`: expected {expected} qubit(s), got {got}")]
GateArity {
gate: String,
expected: usize,
got: usize,
},
#[error("backend `{backend}` does not support: {operation}")]
BackendUnsupported { backend: String, operation: String },
#[error("invalid parameter: {message}")]
InvalidParameter { message: String },
#[error("undefined register `{name}` at line {line}")]
UndefinedRegister { name: String, line: usize },
#[error("cannot export instruction {index} to OpenQASM 3.0: {reason}")]
ExportUnsupported { index: usize, reason: String },
#[error("backend `{backend}` is incompatible: {reason}")]
IncompatibleBackend { backend: String, reason: String },
#[error(
"dynamic program stopped after {max_steps} steps in {region}; raise the bound with `max_steps` if the loop is meant to run that long"
)]
StepLimit { region: String, max_steps: u64 },
#[error("{0}")]
ResourceLimit(Box<ResourceLimit>),
}
#[derive(Debug, Error, Clone, PartialEq)]
#[error(
"backend `{backend}`: {operation} needs {required} {resource}, exceeding the cap of \
{limit} on this machine{}",
override_hint(.env_var)
)]
#[non_exhaustive]
pub struct ResourceLimit {
pub backend: String,
pub operation: String,
pub resource: ResourceKind,
pub required: u128,
pub limit: u128,
pub env_var: Option<&'static str>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ResourceKind {
Qubits,
Amplitudes,
Entries,
Elements,
DeviceBytes,
}
impl std::fmt::Display for ResourceKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
ResourceKind::Qubits => "qubits",
ResourceKind::Amplitudes => "amplitudes",
ResourceKind::Entries => "entries",
ResourceKind::Elements => "elements",
ResourceKind::DeviceBytes => "bytes of device memory",
})
}
}
fn loop_hint(construct: &str) -> &'static str {
match construct {
"while" | "break" | "continue" => {
"; `openqasm::parse_dynamic` reads it into a control-flow graph"
}
_ => "",
}
}
fn override_hint(env_var: &Option<&'static str>) -> String {
env_var.map_or_else(String::new, |var| format!(" (set {var} to override)"))
}
pub type Result<T> = std::result::Result<T, PrismError>;