migrate from anyhow to thiserror (#197)

* migrate from anyhow to thiserror (#190). pending polish error msgs

* Add backtrace and compartmentalize errors

- Include backtraces in the errors we generate.  To get this we can't
  just return a literal enum, because the backtrace requires a call.
- Related to the previous point: add methods to create errors so
  we can include the backtrace conveniently without changing too much
  the syntax.  So instead of `Err(Error::KeyNotFound(key))` (literal
  enum) it will be `Err(Error::key_not_found(key))` (method call)
- Each error should be local to its scope, and each scope should
  only return its own error.
  - The merkle tree should return `TreeError` and not Error
  - The middleware should return `MiddlewareError` and not Error
- With a global Error we can't easily include backend/frontend types in
  the error fields, so declare a `BackendError` and a `FrontendError`
  and follow the pattern from the previous point
- The Pod traits should be able to return backend errors and will be
  used in the frontend; for that we change them to use trait object
  Error: `dyn std::error::Error`

* fix error

* apply suggestions from @arnaucube

* rename XError and XResult to Error and Result

* reorg signature

* make frontend custom error more ergonomic

* remove unnecessary feature

---------

Co-authored-by: Eduard S. <eduardsanou@posteo.net>
This commit is contained in:
arnaucube 2025-04-22 15:07:04 +02:00 committed by GitHub
parent 58d3c6a236
commit 29545f03fc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
31 changed files with 696 additions and 273 deletions

71
src/middleware/error.rs Normal file
View file

@ -0,0 +1,71 @@
//! middleware errors
use std::{backtrace::Backtrace, fmt::Debug};
use crate::middleware::{Operation, Statement, StatementArg};
pub type Result<T, E = Error> = core::result::Result<T, E>;
#[derive(Debug, thiserror::Error)]
pub enum MiddlewareInnerError {
#[error("incorrect statement args")]
IncorrectStatementArgs,
#[error("invalid deduction: {0:?} ⇏ {1:#}")]
InvalidDeduction(Operation, Statement),
#[error("statement argument {0:?} should be a {1}")]
InvalidStatementArg(StatementArg, String),
#[error("{0} {1} is over the limit {2}")]
MaxLength(String, usize, usize),
#[error("{0} amount of {1} should be {1} but it's {2}")]
DiffAmount(String, String, usize, usize),
// Other
#[error("{0}")]
Custom(String),
}
#[derive(thiserror::Error)]
pub enum Error {
#[error("Inner: {inner}\n{backtrace}")]
Inner {
inner: Box<MiddlewareInnerError>,
backtrace: Box<Backtrace>,
},
#[error(transparent)]
Tree(#[from] crate::backends::plonky2::primitives::merkletree::error::TreeError),
}
impl Debug for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self, f)
}
}
macro_rules! new {
($inner:expr) => {
Error::Inner {
inner: Box::new($inner),
backtrace: Box::new(Backtrace::capture()),
}
};
}
use MiddlewareInnerError::*;
impl Error {
pub(crate) fn incorrect_statements_args() -> Self {
new!(IncorrectStatementArgs)
}
pub(crate) fn invalid_deduction(op: Operation, st: Statement) -> Self {
new!(InvalidDeduction(op, st))
}
pub(crate) fn invalid_statement_arg(st_arg: StatementArg, v: String) -> Self {
new!(InvalidStatementArg(st_arg, v))
}
pub(crate) fn max_length(obj: String, found: usize, expect: usize) -> Self {
new!(MaxLength(obj, found, expect))
}
pub(crate) fn diff_amount(obj: String, unit: String, expect: usize, found: usize) -> Self {
new!(DiffAmount(obj, unit, expect, found))
}
pub(crate) fn custom(s: String) -> Self {
new!(Custom(s))
}
}