Skip to main content

bloq/
error.rs

1//! Shared errors for workflows that cross crate boundaries.
2
3use std::error::Error as StdError;
4
5type BoxError = Box<dyn StdError + Send + Sync + 'static>;
6
7/// A result using the facade's [`Error`] by default.
8///
9/// `Result` means `Result<(), Error>`. An explicit error parameter remains
10/// available for functions that need a narrower error type.
11pub type Result<T = (), E = Error> = std::result::Result<T, E>;
12
13/// A small container retaining the typed error from a Bloq workflow.
14///
15/// Subsystem APIs keep their concrete errors. In a function returning [`Result`],
16/// `?` wraps those errors automatically. Use [`Self::downcast_ref`] to inspect
17/// the original error and [`StdError::source`] to traverse its causes.
18/// Application-specific errors can be wrapped with [`Self::new`].
19///
20/// ```
21/// use bloq::prelude::*;
22///
23/// fn circuit_text(source: &str) -> Result<String> {
24///     let graph = parse_blog_to_graph(source)?;
25///     let config = CompileConfig::try_new(3)?;
26///     let artifacts = compile_with(&graph, config)?;
27///     Ok(emit_bloq_stim(&artifacts.bloq)?)
28/// }
29///
30/// let error = circuit_text("invalid BLOG").unwrap_err();
31/// assert!(error.is::<bloq::graph::BlockGraphError>());
32/// ```
33#[derive(Debug, thiserror::Error)]
34#[error("{0}")]
35pub struct Error(#[source] BoxError);
36
37impl Error {
38    /// Wrap an owned error, retaining its type, message, and causes.
39    ///
40    /// ```
41    /// let error = bloq::Error::new("invalid".parse::<u32>().unwrap_err());
42    /// assert!(error.is::<std::num::ParseIntError>());
43    /// ```
44    pub fn new(error: impl StdError + Send + Sync + 'static) -> Self {
45        Self(Box::new(error))
46    }
47
48    /// Whether the original error has type `E`.
49    pub fn is<E: StdError + 'static>(&self) -> bool {
50        self.0.is::<E>()
51    }
52
53    /// Borrow the original error if it has type `E`.
54    pub fn downcast_ref<E: StdError + 'static>(&self) -> Option<&E> {
55        self.0.downcast_ref::<E>()
56    }
57}
58
59impl From<BoxError> for Error {
60    fn from(error: BoxError) -> Self {
61        Self(error)
62    }
63}
64
65// Keep automatic conversions without duplicating subsystem error enums.
66// A blanket From<E> would overlap From<Error> because Error implements StdError.
67macro_rules! impl_from {
68    ($($(#[$meta:meta])* $error:ty),* $(,)?) => {
69        $(
70            $(#[$meta])*
71            impl From<$error> for Error {
72                fn from(error: $error) -> Self {
73                    Self::new(error)
74                }
75            }
76        )*
77    };
78}
79
80impl_from! {
81    bloq_graph::BlockGraphError,
82    bloq_graph::BlockError,
83    bloq_graph::InvalidBlockGraphError,
84    bloq_graph::InvalidActionError,
85    bloq_graph::ParseError,
86    bloq_graph::ModuleError,
87    bloq_graph::ModuleCertificationError,
88    bloq_graph::UnknownCertificationLimit,
89    bloq_graph::ZXError,
90    bloq_graph::FillPortsError,
91    bloq_graph::StabilizerError,
92    bloq_graph::RuntimeBasisError,
93    bloq_graph::SymbolicBasisError,
94    bloq_graph::OutputCorrectionError,
95    bloq_graph::ResolveDomainError,
96    bloq_compile::CompileError,
97    bloq_compile::InvalidDistance,
98    bloq_circuit::CircuitError,
99    bloq_circuit::FlowError,
100    bloq_circuit::MeasurementFrameError,
101    bloq_circuit::DetsliceError,
102    bloq_circuit::CoordinateOverflowError,
103    bloq_ir::BloqValidationError,
104    bloq_ir::BloqStatsError,
105    bloq_ir::TextParseError,
106    bloq_ir::BinaryDecodeError,
107    bloq_ir::CycleDetected,
108    bloq_ir::DetectorBundleError,
109    bloq_ir::FlattenError,
110    bloq_ir::MembershipPinError,
111    bloq_ir::EditError,
112    bloq_ir::StructureError,
113    bloq_ir::ResolveError,
114    bloq_ir::MomentAlignmentError,
115    bloq_ir::ProgramSliceError,
116    bloq_stim::StimEmissionError,
117    bloq_utils::DirectionParseError,
118    bloq_utils::PauliError,
119    bloq_utils::qasm::QasmError,
120    bloq_utils::boolean::BooleanResourceError,
121    strum::ParseError,
122    std::io::Error,
123    #[cfg(feature = "graph-verify")]
124    bloq_graph::verify::VerifyLogicalError,
125    #[cfg(feature = "graph-verify")]
126    bloq_graph::FeedbackInferenceError,
127    #[cfg(feature = "verify")]
128    bloq_stim::StimVerifyError,
129    #[cfg(feature = "verify")]
130    bloq_stim::StimNoiseError,
131    #[cfg(feature = "vm")]
132    bloq_vm::LowerError,
133    #[cfg(feature = "vm")]
134    bloq_vm::RuntimeError,
135    #[cfg(feature = "vm")]
136    bloq_vm::ExecError,
137    #[cfg(feature = "vm")]
138    bloq_vm::SimError,
139    #[cfg(feature = "vm")]
140    bloq_vm::decoder::DecoderError,
141    #[cfg(feature = "vm")]
142    serde_json::Error,
143}