161 lines
4.7 KiB
C
161 lines
4.7 KiB
C
#pragma once
|
|
|
|
#include <jemalloc/jemalloc.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <ksr/logging.h>
|
|
|
|
/**
|
|
* Type of an error code.
|
|
*/
|
|
typedef int ksrerrorcode_t;
|
|
|
|
/**
|
|
* Structure of an error.
|
|
*/
|
|
typedef struct {
|
|
ksrerrorcode_t code;
|
|
char *message;
|
|
void *data;
|
|
} ksrerror;
|
|
|
|
#define KSRERROR_NOERROR_CODE 0
|
|
|
|
/**
|
|
* An error struct that indicates no error.
|
|
*/
|
|
#define ksrerror_none ((ksrerror) { KSRERROR_NOERROR_CODE, NULL, NULL })
|
|
/**
|
|
* Create a new error structure with given code, message and custom error data.
|
|
*/
|
|
#define ksrerror_new_d(error_code, error_message, error_data) ((ksrerror) { error_code, strdup(error_message), error_data })
|
|
/**
|
|
* Create a new error structure with given code and message.
|
|
*/
|
|
#define ksrerror_new(error_code, error_message) ksrerror_new_d(error_code, error_message, NULL)
|
|
|
|
/**
|
|
* Throw a new error structure with given code, message and custom error data.
|
|
*/
|
|
#define ksrerror_throw_d(error_code, error_message, error_data) return ksrerror_new_d(error_code, error_message, error_data)
|
|
/**
|
|
* Throw a new error structure with given code and message.
|
|
*/
|
|
#define ksrerror_throw(error_code, error_message) return ksrerror_new(error_code, error_message)
|
|
|
|
/**
|
|
* Free an error and its custom data, with the given free function.
|
|
*/
|
|
static inline void ksrerror_free_d(ksrerror error, void (*free_data_func)(void*))
|
|
{
|
|
if (error.message) free(error.message);
|
|
if (error.data) free_data_func(error.data);
|
|
}
|
|
/**
|
|
* Free an error without custom data.
|
|
*/
|
|
static inline void ksrerror_free(ksrerror error)
|
|
{
|
|
ksrerror_free_d(error, free);
|
|
}
|
|
|
|
/**
|
|
* Ignore an error and free its custom data.
|
|
*/
|
|
#define ksrerror_ignore_d(error, free_data_func) ksrerror_free_d(error, free_data_func)
|
|
/**
|
|
* Ignore an error without custom data.
|
|
*/
|
|
#define ksrerror_ignore(error) ksrerror_free(error)
|
|
|
|
/**
|
|
* Check if the structure indicates an error.
|
|
* Return true if there is no error, false if there is one.
|
|
*/
|
|
static inline bool ksrerror_check(ksrerror error)
|
|
{
|
|
return error.code == KSRERROR_NOERROR_CODE;
|
|
}
|
|
|
|
/**
|
|
* Propagate the error, if there is one.
|
|
*/
|
|
#define ksrerror_propagate(error) { ksrerror __ksrerror__cache__ = error; if (!ksrerror_check(__ksrerror__cache__)) return __ksrerror__cache__; }
|
|
|
|
/**
|
|
* Panic! Show error message and exit app.
|
|
*/
|
|
#define ksrerror_panic(error) { \
|
|
ksrerror __ksrerror__cache__ = error; \
|
|
if (__ksrerror__cache__.code != KSRERROR_NOERROR_CODE) { \
|
|
char *__ksrerror__error_message__ = malloc(5 + 64 + strlen(__ksrerror__cache__.message) + 1); \
|
|
sprintf(__ksrerror__error_message__, "code %d: %s", __ksrerror__cache__.code, __ksrerror__cache__.message); \
|
|
ksrlog_error(__ksrerror__error_message__); exit(__ksrerror__cache__.code); \
|
|
} }
|
|
|
|
|
|
|
|
/**
|
|
* Structure of a result that can be an error.
|
|
* This structure can be used as a return type for functions that can encounter an error.
|
|
*/
|
|
typedef struct {
|
|
void *result;
|
|
ksrerror error;
|
|
} ksresult;
|
|
|
|
/**
|
|
* Define a result of a specific type.
|
|
*/
|
|
#define ksresult_of_type(result_type) ksresult
|
|
/**
|
|
* Create a new result.
|
|
*/
|
|
#define ksresult_new(_result) ((ksresult) { _result, ksrerror_none })
|
|
/**
|
|
* Create a result that contains an error.
|
|
*/
|
|
#define ksresult_new_error(error) ((ksresult) { NULL, (error) })
|
|
/**
|
|
* Throw an error as a result.
|
|
*/
|
|
#define ksresult_throw(error) return ksresult_new_error(error)
|
|
|
|
/**
|
|
* Try to get a result and put it in the variable called varname.
|
|
* You must specify the type of the result you want to get.
|
|
* If there is an error, it is thrown as a result. You cannot use this function if your function does not return a ksresult.
|
|
*/
|
|
#define ksresult_get(varname, result_type, _result) NULL; { \
|
|
ksresult __ksresult_cache__ = (_result); \
|
|
if (!ksresult_check(__ksresult_cache__)) return __ksresult_cache__; \
|
|
varname = ((result_type) __ksresult_cache__.result); \
|
|
}
|
|
/**
|
|
* Try to get a result and put it in the variable called varname.
|
|
* You must specify the type of the result you want to get.
|
|
* If there is an error, it is thrown directly. You cannot use this function if your function does not return a ksrerror.
|
|
*/
|
|
#define ksresult_get_throwerr(varname, result_type, _result) NULL; { \
|
|
ksresult __ksresult_cache__ = (_result); \
|
|
if (!ksresult_check(__ksresult_cache__)) return __ksresult_cache__.error; \
|
|
varname = ((result_type) __ksresult_cache__.result); \
|
|
}
|
|
/**
|
|
* Try to get a result while ignoring the error if there is one.
|
|
* You must specify the type of the result you want to get.
|
|
* Directly return the result data.
|
|
*/
|
|
#define ksresult_get_ignore(result_type, _result) ((result_type) (_result).result)
|
|
/**
|
|
* Get the error of a result.
|
|
*/
|
|
#define ksresult_error(_result) (_result).error
|
|
/**
|
|
* Check if there is an error in the given result.
|
|
*/
|
|
#define ksresult_check(_result) ksrerror_check(ksresult_error(_result))
|
|
|
|
|