2022-12-19 20:50:40 +01:00
use std ::{ fmt , io } ;
2021-03-10 13:46:49 +01:00
2022-10-20 18:00:07 +02:00
use actix_web ::http ::StatusCode ;
use actix_web ::{ self as aweb , HttpResponseBuilder } ;
2022-09-27 16:33:37 +02:00
use aweb ::rt ::task ::JoinError ;
2023-01-02 16:13:44 +01:00
use convert_case ::Casing ;
2022-10-04 11:07:14 +02:00
use milli ::heed ::{ Error as HeedError , MdbError } ;
2021-09-27 15:41:14 +02:00
use serde ::{ Deserialize , Serialize } ;
2023-01-11 12:33:56 +01:00
2021-12-02 16:03:26 +01:00
#[ derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq) ]
#[ serde(rename_all = " camelCase " ) ]
pub struct ResponseError {
#[ serde(skip) ]
2023-02-21 17:24:23 +01:00
pub code : StatusCode ,
pub message : String ,
2021-12-02 16:03:26 +01:00
#[ serde(rename = " code " ) ]
error_code : String ,
#[ serde(rename = " type " ) ]
error_type : String ,
#[ serde(rename = " link " ) ]
error_link : String ,
}
impl ResponseError {
2022-12-20 17:31:13 +01:00
pub fn from_msg ( mut message : String , code : Code ) -> Self {
if code = = Code ::IoError {
message . push_str ( " . This error generally happens when you have no space left on device or when your database doesn't have read or write right. " ) ;
}
2021-12-02 16:03:26 +01:00
Self {
code : code . http ( ) ,
message ,
2023-01-16 16:59:26 +01:00
error_code : code . name ( ) ,
2021-12-02 16:03:26 +01:00
error_type : code . type_ ( ) ,
error_link : code . url ( ) ,
}
}
}
impl fmt ::Display for ResponseError {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
self . message . fmt ( f )
}
}
impl std ::error ::Error for ResponseError { }
impl < T > From < T > for ResponseError
where
2023-01-11 12:33:45 +01:00
T : std ::error ::Error + ErrorCode ,
2021-12-02 16:03:26 +01:00
{
fn from ( other : T ) -> Self {
2022-12-20 17:31:13 +01:00
Self ::from_msg ( other . to_string ( ) , other . error_code ( ) )
2021-12-02 16:03:26 +01:00
}
}
impl aweb ::error ::ResponseError for ResponseError {
2022-01-21 21:44:17 +01:00
fn error_response ( & self ) -> aweb ::HttpResponse {
2021-12-02 16:03:26 +01:00
let json = serde_json ::to_vec ( self ) . unwrap ( ) ;
2022-10-20 18:00:07 +02:00
HttpResponseBuilder ::new ( self . status_code ( ) ) . content_type ( " application/json " ) . body ( json )
2021-12-02 16:03:26 +01:00
}
fn status_code ( & self ) -> StatusCode {
self . code
}
}
2023-01-11 12:33:45 +01:00
pub trait ErrorCode {
2021-03-10 13:46:49 +01:00
fn error_code ( & self ) -> Code ;
2022-06-05 04:38:04 +02:00
/// returns the HTTP status code associated with the error
2021-03-10 13:46:49 +01:00
fn http_status ( & self ) -> StatusCode {
self . error_code ( ) . http ( )
}
2022-06-05 04:38:04 +02:00
/// returns the doc url associated with the error
2021-03-10 13:46:49 +01:00
fn error_url ( & self ) -> String {
self . error_code ( ) . url ( )
}
/// returns error name, used as error code
fn error_name ( & self ) -> String {
self . error_code ( ) . name ( )
}
/// return the error type
fn error_type ( & self ) -> String {
self . error_code ( ) . type_ ( )
}
}
#[ allow(clippy::enum_variant_names) ]
enum ErrorType {
2023-01-16 16:59:26 +01:00
Internal ,
InvalidRequest ,
Auth ,
2023-01-05 21:06:50 +01:00
System ,
2021-03-10 13:46:49 +01:00
}
impl fmt ::Display for ErrorType {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
use ErrorType ::* ;
match self {
2023-01-16 16:59:26 +01:00
Internal = > write! ( f , " internal " ) ,
InvalidRequest = > write! ( f , " invalid_request " ) ,
Auth = > write! ( f , " auth " ) ,
2023-01-05 21:06:50 +01:00
System = > write! ( f , " system " ) ,
2021-03-10 13:46:49 +01:00
}
}
}
2023-01-16 16:59:26 +01:00
/// Implement all the error codes.
///
/// 1. Make an enum `Code` where each error code is a variant
/// 2. Implement the `http`, `name`, and `type_` method on the enum
/// 3. Make a unit type for each error code in the module `deserr_codes`.
///
/// The unit type's purpose is to be used as a marker type parameter, e.g.
/// `DeserrJsonError<MyErrorCode>`. It implements `Default` and `ErrorCode`,
/// so we can get a value of the `Code` enum with the correct variant by calling
/// `MyErrorCode::default().error_code()`.
2023-01-11 12:33:45 +01:00
macro_rules ! make_error_codes {
( $( $code_ident :ident , $err_type :ident , $status :ident ) ; * ) = > {
#[ derive(Debug, Clone, Copy, PartialEq, Eq) ]
pub enum Code {
$( $code_ident ) , *
}
impl Code {
2023-01-16 16:59:26 +01:00
/// return the HTTP status code associated with the `Code`
2023-02-14 13:12:42 +01:00
pub fn http ( & self ) -> StatusCode {
2023-01-11 12:33:45 +01:00
match self {
$(
2023-01-16 16:59:26 +01:00
Code ::$code_ident = > StatusCode ::$status
) , *
2023-01-11 12:33:45 +01:00
}
2022-12-14 13:00:43 +01:00
}
2023-01-11 12:33:45 +01:00
/// return error name, used as error code
fn name ( & self ) -> String {
2023-01-16 16:59:26 +01:00
match self {
$(
Code ::$code_ident = > stringify! ( $code_ident ) . to_case ( convert_case ::Case ::Snake )
) , *
}
2022-12-14 13:00:43 +01:00
}
2023-01-11 12:33:45 +01:00
/// return the error type
fn type_ ( & self ) -> String {
2023-01-16 16:59:26 +01:00
match self {
$(
Code ::$code_ident = > ErrorType ::$err_type . to_string ( )
) , *
}
2022-12-14 13:00:43 +01:00
}
2023-01-08 11:59:01 +01:00
2023-01-11 12:33:45 +01:00
/// return the doc url associated with the error
fn url ( & self ) -> String {
2023-01-19 15:47:01 +01:00
format! ( " https://docs.meilisearch.com/errors# {} " , self . name ( ) )
2023-01-08 11:59:01 +01:00
}
2021-03-10 13:46:49 +01:00
}
2023-01-11 12:33:45 +01:00
pub mod deserr_codes {
use super ::{ Code , ErrorCode } ;
$(
#[ derive(Default) ]
pub struct $code_ident ;
impl ErrorCode for $code_ident {
fn error_code ( & self ) -> Code {
Code ::$code_ident
}
}
) *
}
2021-03-10 13:46:49 +01:00
}
2023-01-11 12:33:45 +01:00
}
2021-03-10 13:46:49 +01:00
2023-01-16 16:59:26 +01:00
// An exhaustive list of all the error codes used by meilisearch.
make_error_codes! {
ApiKeyAlreadyExists , InvalidRequest , CONFLICT ;
ApiKeyNotFound , InvalidRequest , NOT_FOUND ;
BadParameter , InvalidRequest , BAD_REQUEST ;
BadRequest , InvalidRequest , BAD_REQUEST ;
DatabaseSizeLimitReached , Internal , INTERNAL_SERVER_ERROR ;
DocumentNotFound , InvalidRequest , NOT_FOUND ;
DumpAlreadyProcessing , InvalidRequest , CONFLICT ;
DumpNotFound , InvalidRequest , NOT_FOUND ;
DumpProcessFailed , Internal , INTERNAL_SERVER_ERROR ;
DuplicateIndexFound , InvalidRequest , BAD_REQUEST ;
ImmutableApiKeyActions , InvalidRequest , BAD_REQUEST ;
ImmutableApiKeyCreatedAt , InvalidRequest , BAD_REQUEST ;
ImmutableApiKeyExpiresAt , InvalidRequest , BAD_REQUEST ;
ImmutableApiKeyIndexes , InvalidRequest , BAD_REQUEST ;
ImmutableApiKeyKey , InvalidRequest , BAD_REQUEST ;
ImmutableApiKeyUid , InvalidRequest , BAD_REQUEST ;
ImmutableApiKeyUpdatedAt , InvalidRequest , BAD_REQUEST ;
ImmutableIndexCreatedAt , InvalidRequest , BAD_REQUEST ;
ImmutableIndexUid , InvalidRequest , BAD_REQUEST ;
ImmutableIndexUpdatedAt , InvalidRequest , BAD_REQUEST ;
IndexAlreadyExists , InvalidRequest , CONFLICT ;
IndexCreationFailed , Internal , INTERNAL_SERVER_ERROR ;
IndexNotFound , InvalidRequest , NOT_FOUND ;
IndexPrimaryKeyAlreadyExists , InvalidRequest , BAD_REQUEST ;
IndexPrimaryKeyMultipleCandidatesFound , InvalidRequest , BAD_REQUEST ;
IndexPrimaryKeyNoCandidateFound , InvalidRequest , BAD_REQUEST ;
Internal , Internal , INTERNAL_SERVER_ERROR ;
InvalidApiKey , Auth , FORBIDDEN ;
InvalidApiKeyActions , InvalidRequest , BAD_REQUEST ;
InvalidApiKeyDescription , InvalidRequest , BAD_REQUEST ;
InvalidApiKeyExpiresAt , InvalidRequest , BAD_REQUEST ;
InvalidApiKeyIndexes , InvalidRequest , BAD_REQUEST ;
InvalidApiKeyLimit , InvalidRequest , BAD_REQUEST ;
InvalidApiKeyName , InvalidRequest , BAD_REQUEST ;
InvalidApiKeyOffset , InvalidRequest , BAD_REQUEST ;
InvalidApiKeyUid , InvalidRequest , BAD_REQUEST ;
InvalidContentType , InvalidRequest , UNSUPPORTED_MEDIA_TYPE ;
2023-02-22 19:26:48 +01:00
InvalidDocumentCsvDelimiter , InvalidRequest , BAD_REQUEST ;
2023-01-16 16:59:26 +01:00
InvalidDocumentFields , InvalidRequest , BAD_REQUEST ;
2023-05-24 11:29:20 +02:00
MissingDocumentFilter , InvalidRequest , BAD_REQUEST ;
2023-05-04 15:19:17 +02:00
InvalidDocumentFilter , InvalidRequest , BAD_REQUEST ;
2023-01-16 16:59:26 +01:00
InvalidDocumentGeoField , InvalidRequest , BAD_REQUEST ;
2023-06-14 16:34:09 +02:00
InvalidVectorDimensions , InvalidRequest , BAD_REQUEST ;
2023-06-20 16:18:24 +02:00
InvalidVectorsType , InvalidRequest , BAD_REQUEST ;
2023-01-16 16:59:26 +01:00
InvalidDocumentId , InvalidRequest , BAD_REQUEST ;
InvalidDocumentLimit , InvalidRequest , BAD_REQUEST ;
InvalidDocumentOffset , InvalidRequest , BAD_REQUEST ;
InvalidIndexLimit , InvalidRequest , BAD_REQUEST ;
InvalidIndexOffset , InvalidRequest , BAD_REQUEST ;
InvalidIndexPrimaryKey , InvalidRequest , BAD_REQUEST ;
InvalidIndexUid , InvalidRequest , BAD_REQUEST ;
2023-06-20 10:00:35 +02:00
InvalidAttributesToSearchOn , InvalidRequest , BAD_REQUEST ;
2023-01-16 16:59:26 +01:00
InvalidSearchAttributesToCrop , InvalidRequest , BAD_REQUEST ;
InvalidSearchAttributesToHighlight , InvalidRequest , BAD_REQUEST ;
InvalidSearchAttributesToRetrieve , InvalidRequest , BAD_REQUEST ;
InvalidSearchCropLength , InvalidRequest , BAD_REQUEST ;
InvalidSearchCropMarker , InvalidRequest , BAD_REQUEST ;
InvalidSearchFacets , InvalidRequest , BAD_REQUEST ;
InvalidSearchFilter , InvalidRequest , BAD_REQUEST ;
InvalidSearchHighlightPostTag , InvalidRequest , BAD_REQUEST ;
InvalidSearchHighlightPreTag , InvalidRequest , BAD_REQUEST ;
InvalidSearchHitsPerPage , InvalidRequest , BAD_REQUEST ;
InvalidSearchLimit , InvalidRequest , BAD_REQUEST ;
InvalidSearchMatchingStrategy , InvalidRequest , BAD_REQUEST ;
InvalidSearchOffset , InvalidRequest , BAD_REQUEST ;
InvalidSearchPage , InvalidRequest , BAD_REQUEST ;
InvalidSearchQ , InvalidRequest , BAD_REQUEST ;
2023-06-26 18:07:56 +02:00
InvalidSearchVector , InvalidRequest , BAD_REQUEST ;
2023-01-16 16:59:26 +01:00
InvalidSearchShowMatchesPosition , InvalidRequest , BAD_REQUEST ;
2023-06-06 18:26:33 +02:00
InvalidSearchShowRankingScore , InvalidRequest , BAD_REQUEST ;
InvalidSearchShowRankingScoreDetails , InvalidRequest , BAD_REQUEST ;
2023-01-16 16:59:26 +01:00
InvalidSearchSort , InvalidRequest , BAD_REQUEST ;
InvalidSettingsDisplayedAttributes , InvalidRequest , BAD_REQUEST ;
InvalidSettingsDistinctAttribute , InvalidRequest , BAD_REQUEST ;
InvalidSettingsFaceting , InvalidRequest , BAD_REQUEST ;
InvalidSettingsFilterableAttributes , InvalidRequest , BAD_REQUEST ;
InvalidSettingsPagination , InvalidRequest , BAD_REQUEST ;
InvalidSettingsRankingRules , InvalidRequest , BAD_REQUEST ;
InvalidSettingsSearchableAttributes , InvalidRequest , BAD_REQUEST ;
InvalidSettingsSortableAttributes , InvalidRequest , BAD_REQUEST ;
InvalidSettingsStopWords , InvalidRequest , BAD_REQUEST ;
InvalidSettingsSynonyms , InvalidRequest , BAD_REQUEST ;
InvalidSettingsTypoTolerance , InvalidRequest , BAD_REQUEST ;
InvalidState , Internal , INTERNAL_SERVER_ERROR ;
InvalidStoreFile , Internal , INTERNAL_SERVER_ERROR ;
InvalidSwapDuplicateIndexFound , InvalidRequest , BAD_REQUEST ;
InvalidSwapIndexes , InvalidRequest , BAD_REQUEST ;
InvalidTaskAfterEnqueuedAt , InvalidRequest , BAD_REQUEST ;
InvalidTaskAfterFinishedAt , InvalidRequest , BAD_REQUEST ;
InvalidTaskAfterStartedAt , InvalidRequest , BAD_REQUEST ;
InvalidTaskBeforeEnqueuedAt , InvalidRequest , BAD_REQUEST ;
InvalidTaskBeforeFinishedAt , InvalidRequest , BAD_REQUEST ;
InvalidTaskBeforeStartedAt , InvalidRequest , BAD_REQUEST ;
InvalidTaskCanceledBy , InvalidRequest , BAD_REQUEST ;
InvalidTaskFrom , InvalidRequest , BAD_REQUEST ;
InvalidTaskLimit , InvalidRequest , BAD_REQUEST ;
InvalidTaskStatuses , InvalidRequest , BAD_REQUEST ;
InvalidTaskTypes , InvalidRequest , BAD_REQUEST ;
InvalidTaskUids , InvalidRequest , BAD_REQUEST ;
IoError , System , UNPROCESSABLE_ENTITY ;
2023-06-22 22:56:44 +02:00
FeatureNotEnabled , InvalidRequest , BAD_REQUEST ;
2023-01-16 16:59:26 +01:00
MalformedPayload , InvalidRequest , BAD_REQUEST ;
MaxFieldsLimitExceeded , InvalidRequest , BAD_REQUEST ;
MissingApiKeyActions , InvalidRequest , BAD_REQUEST ;
MissingApiKeyExpiresAt , InvalidRequest , BAD_REQUEST ;
MissingApiKeyIndexes , InvalidRequest , BAD_REQUEST ;
MissingAuthorizationHeader , Auth , UNAUTHORIZED ;
MissingContentType , InvalidRequest , UNSUPPORTED_MEDIA_TYPE ;
MissingDocumentId , InvalidRequest , BAD_REQUEST ;
MissingIndexUid , InvalidRequest , BAD_REQUEST ;
MissingMasterKey , Auth , UNAUTHORIZED ;
MissingPayload , InvalidRequest , BAD_REQUEST ;
MissingSwapIndexes , InvalidRequest , BAD_REQUEST ;
MissingTaskFilters , InvalidRequest , BAD_REQUEST ;
NoSpaceLeftOnDevice , System , UNPROCESSABLE_ENTITY ;
PayloadTooLarge , InvalidRequest , PAYLOAD_TOO_LARGE ;
TaskNotFound , InvalidRequest , NOT_FOUND ;
TooManyOpenFiles , System , UNPROCESSABLE_ENTITY ;
UnretrievableDocument , Internal , BAD_REQUEST ;
UnretrievableErrorCode , InvalidRequest , BAD_REQUEST ;
UnsupportedMediaType , InvalidRequest , UNSUPPORTED_MEDIA_TYPE
2021-03-10 13:46:49 +01:00
}
2021-12-02 16:03:26 +01:00
2022-09-27 16:33:37 +02:00
impl ErrorCode for JoinError {
fn error_code ( & self ) -> Code {
Code ::Internal
}
}
2022-10-04 10:38:17 +02:00
impl ErrorCode for milli ::Error {
fn error_code ( & self ) -> Code {
use milli ::{ Error , UserError } ;
match self {
Error ::InternalError ( _ ) = > Code ::Internal ,
2022-12-19 20:50:40 +01:00
Error ::IoError ( e ) = > e . error_code ( ) ,
2022-10-04 10:38:17 +02:00
Error ::UserError ( ref error ) = > {
match error {
// TODO: wait for spec for new error codes.
UserError ::SerdeJson ( _ )
| UserError ::InvalidLmdbOpenOptions
| UserError ::DocumentLimitReached
| UserError ::AccessingSoftDeletedDocument { .. }
| UserError ::UnknownInternalDocumentId { .. } = > Code ::Internal ,
2023-01-11 12:33:45 +01:00
UserError ::InvalidStoreFile = > Code ::InvalidStoreFile ,
2022-10-04 10:38:17 +02:00
UserError ::NoSpaceLeftOnDevice = > Code ::NoSpaceLeftOnDevice ,
UserError ::MaxDatabaseSizeReached = > Code ::DatabaseSizeLimitReached ,
UserError ::AttributeLimitReached = > Code ::MaxFieldsLimitExceeded ,
2023-01-09 18:59:09 +01:00
UserError ::InvalidFilter ( _ ) = > Code ::InvalidSearchFilter ,
2023-03-07 10:02:04 +01:00
UserError ::InvalidFilterExpression ( .. ) = > Code ::InvalidSearchFilter ,
2022-10-04 10:38:17 +02:00
UserError ::MissingDocumentId { .. } = > Code ::MissingDocumentId ,
UserError ::InvalidDocumentId { .. } | UserError ::TooManyDocumentIds { .. } = > {
Code ::InvalidDocumentId
}
2023-01-11 12:33:45 +01:00
UserError ::NoPrimaryKeyCandidateFound = > Code ::IndexPrimaryKeyNoCandidateFound ,
2022-12-21 12:02:01 +01:00
UserError ::MultiplePrimaryKeyCandidatesFound { .. } = > {
2023-01-11 12:33:45 +01:00
Code ::IndexPrimaryKeyMultipleCandidatesFound
2022-12-21 12:02:01 +01:00
}
2023-01-11 12:33:45 +01:00
UserError ::PrimaryKeyCannotBeChanged ( _ ) = > Code ::IndexPrimaryKeyAlreadyExists ,
2023-01-09 18:59:09 +01:00
UserError ::SortRankingRuleMissing = > Code ::InvalidSearchSort ,
2023-01-19 11:25:55 +01:00
UserError ::InvalidFacetsDistribution { .. } = > Code ::InvalidSearchFacets ,
2023-01-09 18:59:09 +01:00
UserError ::InvalidSortableAttribute { .. } = > Code ::InvalidSearchSort ,
2023-06-20 17:04:59 +02:00
UserError ::InvalidSearchableAttribute { .. } = > {
Code ::InvalidAttributesToSearchOn
}
2023-01-11 14:31:34 +01:00
UserError ::CriterionError ( _ ) = > Code ::InvalidSettingsRankingRules ,
2023-01-05 21:08:19 +01:00
UserError ::InvalidGeoField { .. } = > Code ::InvalidDocumentGeoField ,
2023-06-14 16:34:09 +02:00
UserError ::InvalidVectorDimensions { .. } = > Code ::InvalidVectorDimensions ,
2023-06-20 16:18:24 +02:00
UserError ::InvalidVectorsType { .. } = > Code ::InvalidVectorsType ,
2023-01-09 18:59:09 +01:00
UserError ::SortError ( _ ) = > Code ::InvalidSearchSort ,
2022-10-04 10:38:17 +02:00
UserError ::InvalidMinTypoWordLenSetting ( _ , _ ) = > {
2023-01-18 12:28:46 +01:00
Code ::InvalidSettingsTypoTolerance
2022-10-04 10:38:17 +02:00
}
}
}
}
}
}
2022-12-19 20:50:40 +01:00
impl ErrorCode for file_store ::Error {
fn error_code ( & self ) -> Code {
match self {
Self ::IoError ( e ) = > e . error_code ( ) ,
Self ::PersistError ( e ) = > e . error_code ( ) ,
2023-01-24 16:17:23 +01:00
Self ::CouldNotParseFileNameAsUtf8 | Self ::UuidError ( _ ) = > Code ::Internal ,
2022-12-19 20:50:40 +01:00
}
}
}
impl ErrorCode for tempfile ::PersistError {
fn error_code ( & self ) -> Code {
self . error . error_code ( )
}
}
2022-10-04 11:07:14 +02:00
impl ErrorCode for HeedError {
fn error_code ( & self ) -> Code {
match self {
HeedError ::Mdb ( MdbError ::MapFull ) = > Code ::DatabaseSizeLimitReached ,
2023-01-11 12:33:45 +01:00
HeedError ::Mdb ( MdbError ::Invalid ) = > Code ::InvalidStoreFile ,
2022-12-19 20:50:40 +01:00
HeedError ::Io ( e ) = > e . error_code ( ) ,
HeedError ::Mdb ( _ )
2022-10-04 11:07:14 +02:00
| HeedError ::Encoding
| HeedError ::Decoding
| HeedError ::InvalidDatabaseTyping
| HeedError ::DatabaseClosing
| HeedError ::BadOpenOptions = > Code ::Internal ,
}
}
}
2022-12-19 20:50:40 +01:00
impl ErrorCode for io ::Error {
fn error_code ( & self ) -> Code {
match self . raw_os_error ( ) {
Some ( 5 ) = > Code ::IoError ,
Some ( 24 ) = > Code ::TooManyOpenFiles ,
Some ( 28 ) = > Code ::NoSpaceLeftOnDevice ,
2022-12-20 16:32:51 +01:00
_ = > Code ::Internal ,
2022-12-19 20:50:40 +01:00
}
}
}
2023-01-16 16:59:26 +01:00
/// Deserialization when `deserr` cannot parse an API key date.
#[ derive(Debug) ]
pub struct ParseOffsetDateTimeError ( pub String ) ;
impl fmt ::Display for ParseOffsetDateTimeError {
2023-01-11 12:33:56 +01:00
fn fmt ( & self , f : & mut std ::fmt ::Formatter < '_ > ) -> std ::fmt ::Result {
2023-01-16 16:59:26 +01:00
writeln! ( f , " `{original}` is not a valid date. It should follow the RFC 3339 format to represents a date or datetime in the future or specified as a null value. e.g. 'YYYY-MM-DD' or 'YYYY-MM-DD HH:MM:SS'. " , original = self . 0 )
2023-01-12 13:55:53 +01:00
}
}
2023-01-16 16:59:26 +01:00
/// Deserialization when `deserr` cannot parse a task date.
#[ derive(Debug) ]
pub struct InvalidTaskDateError ( pub String ) ;
impl std ::fmt ::Display for InvalidTaskDateError {
fn fmt ( & self , f : & mut std ::fmt ::Formatter < '_ > ) -> std ::fmt ::Result {
write! ( f , " `{}` is an invalid date-time. It should follow the YYYY-MM-DD or RFC 3339 date-time format. " , self . 0 )
2023-01-11 12:33:56 +01:00
}
}
2023-01-16 16:59:26 +01:00
/// Deserialization error when `deserr` cannot parse a String
/// into a bool.
#[ derive(Debug) ]
pub struct DeserrParseBoolError ( pub String ) ;
impl fmt ::Display for DeserrParseBoolError {
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
write! ( f , " could not parse `{}` as a boolean, expected either `true` or `false` " , self . 0 )
2023-01-12 13:55:53 +01:00
}
}
2023-01-16 16:59:26 +01:00
/// Deserialization error when `deserr` cannot parse a String
/// into an integer.
2023-01-12 13:55:53 +01:00
#[ derive(Debug) ]
2023-01-16 16:59:26 +01:00
pub struct DeserrParseIntError ( pub String ) ;
impl fmt ::Display for DeserrParseIntError {
2023-01-12 13:55:53 +01:00
fn fmt ( & self , f : & mut fmt ::Formatter < '_ > ) -> fmt ::Result {
write! ( f , " could not parse `{}` as a positive integer " , self . 0 )
}
}
2023-01-11 12:33:56 +01:00
2021-11-08 18:31:27 +01:00
#[ macro_export ]
macro_rules ! internal_error {
( $target :ty : $( $other :path ) , * ) = > {
$(
impl From < $other > for $target {
fn from ( other : $other ) -> Self {
Self ::Internal ( Box ::new ( other ) )
}
}
) *
}
}