use std::{fmt, fmt::Debug, str::Utf8Error}; #[derive(thiserror::Error, Clone, Debug)] pub struct OTError { pub code: OTErrorCode, pub msg: String, } macro_rules! static_ot_error { ($name:ident, $code:expr) => { #[allow(non_snake_case, missing_docs)] pub fn $name() -> OTError { $code.into() } }; } impl std::convert::From for OTError { fn from(code: OTErrorCode) -> Self { OTError { code: code.clone(), msg: format!("{:?}", code), } } } impl OTError { pub fn new(code: OTErrorCode, msg: &str) -> OTError { Self { code, msg: msg.to_owned(), } } pub fn context(mut self, error: T) -> Self { self.msg = format!("{:?}", error); self } static_ot_error!(duplicate_revision, OTErrorCode::DuplicatedRevision); static_ot_error!(revision_id_conflict, OTErrorCode::RevisionIDConflict); static_ot_error!(internal, OTErrorCode::Internal); } impl fmt::Display for OTError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "incompatible lengths") } } impl std::convert::From for OTError { fn from(error: serde_json::Error) -> Self { ErrorBuilder::new(OTErrorCode::SerdeError).error(error).build() } } impl std::convert::From for OTError { fn from(error: Utf8Error) -> Self { ErrorBuilder::new(OTErrorCode::SerdeError).error(error).build() } } #[derive(Debug, Clone)] pub enum OTErrorCode { IncompatibleLength, ApplyInsertFail, ApplyDeleteFail, ApplyFormatFail, ComposeOperationFail, IntervalOutOfBound, UndoFail, RedoFail, SerdeError, DuplicatedRevision, RevisionIDConflict, Internal, } pub struct ErrorBuilder { pub code: OTErrorCode, pub msg: Option, } impl ErrorBuilder { pub fn new(code: OTErrorCode) -> Self { ErrorBuilder { code, msg: None } } pub fn msg(mut self, msg: T) -> Self where T: Into, { self.msg = Some(msg.into()); self } pub fn error(mut self, msg: T) -> Self where T: std::fmt::Debug, { self.msg = Some(format!("{:?}", msg)); self } pub fn build(mut self) -> OTError { OTError::new(self.code, &self.msg.take().unwrap_or_else(|| "".to_owned())) } }