error.rs
1 use error_stack::{report, Context, Report, ResultExt}; 2 use std::fmt; 3 4 #[derive(Debug)] 5 pub enum RunnerError { 6 Internal(String), 7 MissingArgument(String), 8 InvalidArgument(String, String), 9 NotFound(String), 10 AlreadyExists(String), 11 } 12 impl RunnerError { 13 pub fn internal(message: &str) -> Report<RunnerError> { 14 report!(RunnerError::Internal(message.to_string())).attach_printable(message.to_string()) 15 } 16 pub fn missing_argument(argument: &str) -> Report<RunnerError> { 17 report!(RunnerError::MissingArgument(argument.to_string())) 18 .attach_printable(format!("missing required argument: {argument}")) 19 } 20 pub fn invalid_argument(argument: &str, reason: &str) -> Report<RunnerError> { 21 report!(RunnerError::InvalidArgument( 22 argument.to_string(), 23 reason.to_string() 24 )) 25 .attach_printable(format!("invalid argument {argument}: {reason}")) 26 } 27 pub fn not_found(name: &str) -> Report<RunnerError> { 28 report!(RunnerError::NotFound(name.to_string())) 29 .attach_printable(format!("{} not found", name)) 30 } 31 pub fn already_exists(name: &str) -> Report<RunnerError> { 32 report!(RunnerError::AlreadyExists(name.to_string())) 33 .attach_printable(format!("{} already exists", name)) 34 } 35 36 pub fn to_tonic_status(&self) -> tonic::Status { 37 match self { 38 // TODO: include the internal error message in the tonic message but only for local runner 39 RunnerError::Internal(_message) => tonic::Status::internal("internal error"), 40 RunnerError::MissingArgument(argument) => { 41 tonic::Status::invalid_argument(format!("missing required argument: {argument}")) 42 } 43 RunnerError::InvalidArgument(argument, reason) => { 44 tonic::Status::invalid_argument(format!("invalid argument {argument}: {reason}")) 45 } 46 RunnerError::NotFound(name) => tonic::Status::not_found(format!("{} not found", name)), 47 RunnerError::AlreadyExists(name) => { 48 tonic::Status::already_exists(format!("{} already exists", name)) 49 } 50 } 51 } 52 } 53 impl Context for RunnerError {} 54 impl fmt::Display for RunnerError { 55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 56 f.write_str("local runner failed") 57 } 58 } 59 60 pub type RunnerResult<T> = error_stack::Result<T, RunnerError>; 61 62 pub trait RunnerResultExt { 63 type Ok; 64 fn internal(self, message: &str) -> RunnerResult<Self::Ok>; 65 fn missing_argument(self, argument: &str) -> RunnerResult<Self::Ok>; 66 fn invalid_argument(self, argument: &str, reason: &str) -> RunnerResult<Self::Ok>; 67 fn not_found(self, name: &str) -> RunnerResult<Self::Ok>; 68 fn already_exists(self, name: &str) -> RunnerResult<Self::Ok>; 69 } 70 71 pub trait RunnerReportExt { 72 fn internal(self, message: &str) -> Report<RunnerError>; 73 } 74 75 impl<T, C> RunnerResultExt for core::result::Result<T, C> 76 where 77 C: Context, 78 { 79 type Ok = T; 80 81 fn internal(self, message: &str) -> RunnerResult<T> { 82 self.change_context(RunnerError::Internal(message.to_string())) 83 .attach_printable(message.to_string()) 84 } 85 86 fn missing_argument(self, argument: &str) -> RunnerResult<T> { 87 self.change_context(RunnerError::MissingArgument(argument.to_string())) 88 .attach_printable(format!("missing required argument {argument}")) 89 } 90 91 fn invalid_argument(self, argument: &str, reason: &str) -> RunnerResult<T> { 92 self.change_context(RunnerError::InvalidArgument( 93 argument.to_string(), 94 reason.to_string(), 95 )) 96 .attach_printable(format!("invalid argument {argument}: {reason}")) 97 } 98 99 fn not_found(self, name: &str) -> RunnerResult<T> { 100 self.change_context(RunnerError::NotFound(name.to_string())) 101 .attach_printable(format!("{name} not found")) 102 } 103 104 fn already_exists(self, name: &str) -> RunnerResult<T> { 105 self.change_context(RunnerError::AlreadyExists(name.to_string())) 106 .attach_printable(format!("{name} already exists")) 107 } 108 } 109 110 impl<C> RunnerReportExt for Report<C> { 111 fn internal(self, message: &str) -> Report<RunnerError> { 112 self.change_context(RunnerError::Internal(message.to_string())) 113 .attach_printable(message.to_string()) 114 } 115 }