mirror of
https://github.com/arcan1s/result.git
synced 2025-04-24 07:27:18 +00:00
262 lines
6.9 KiB
C++
262 lines
6.9 KiB
C++
/*
|
|
* Copyright (c) 2017 Evgeniy Alekseev
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
*
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*/
|
|
|
|
|
|
#ifndef _RESULT_HPP_
|
|
#define _RESULT_HPP_
|
|
|
|
#include <string>
|
|
#include <variant>
|
|
|
|
/**
|
|
* @addtogroup Result
|
|
* @brief Result namespace
|
|
*/
|
|
namespace Result
|
|
{
|
|
/**
|
|
* @enum Content
|
|
* @brief Result content type enumeration
|
|
* @var Content::Empty
|
|
* invalid content
|
|
* @var Content::Value
|
|
* Result contains value
|
|
* @var Content::Error
|
|
* Result contains error
|
|
*/
|
|
enum class Content { Empty, Value, Error };
|
|
|
|
/**
|
|
* @brief Error representation
|
|
* @tparam ErrorEnum
|
|
* error code enumeration
|
|
*/
|
|
template <typename ErrorEnum> class Error
|
|
{
|
|
public:
|
|
/**
|
|
* @brief default class constructor
|
|
*/
|
|
Error() = default;
|
|
/**
|
|
* @brief Error class constructor
|
|
* @param message
|
|
* human readable error message
|
|
* @param code
|
|
* machine readable error code
|
|
*/
|
|
Error(const std::string message, const ErrorEnum code)
|
|
: m_code(code)
|
|
{
|
|
m_message = std::move(message);
|
|
};
|
|
/**
|
|
* @brief Error class constructor with default error code
|
|
* @param message
|
|
* human readable error message
|
|
*/
|
|
Error(const ErrorEnum code)
|
|
: Error("", code){};
|
|
/**
|
|
* @brief Error class constructor with empty error message
|
|
* @param code
|
|
* machine readable error code
|
|
*/
|
|
Error(const std::string message)
|
|
: Error(message, ErrorEnum()){};
|
|
/**
|
|
* @brief Error class destructor
|
|
*/
|
|
~Error() = default;
|
|
|
|
/**
|
|
* @brief error message
|
|
* @return human readable error message
|
|
*/
|
|
std::string message() const { return m_message; };
|
|
/**
|
|
* @brief error code
|
|
* @return machine readable error code
|
|
*/
|
|
ErrorEnum code() const { return m_code; };
|
|
|
|
private:
|
|
/**
|
|
* @brief human readable error message
|
|
*/
|
|
std::string m_message;
|
|
/**
|
|
* @brief machine readable error code
|
|
*/
|
|
ErrorEnum m_code;
|
|
};
|
|
|
|
/**
|
|
* @brief Result main class
|
|
* @tparam T
|
|
* value class name
|
|
* @tparam ErrorEnum
|
|
* error code enumeration
|
|
*/
|
|
template <typename T, typename ErrorEnum>
|
|
class Result : public std::variant<T, Error<ErrorEnum>>
|
|
{
|
|
public:
|
|
/**
|
|
* @brief default class constructor
|
|
*/
|
|
Result() = default;
|
|
/**
|
|
* @brief Result constructor with value
|
|
* @param value
|
|
* result value
|
|
*/
|
|
Result(const T value)
|
|
: std::variant<T, Error<ErrorEnum>>(value){};
|
|
/**
|
|
* @brief Result constructor with error
|
|
* @param error
|
|
* result error
|
|
*/
|
|
Result(const Error<ErrorEnum> error)
|
|
: std::variant<T, Error<ErrorEnum>>(error){};
|
|
|
|
/**
|
|
* @brief get result value
|
|
* @throw std::bad_variant_access
|
|
* @return result value if holded
|
|
*/
|
|
T get() const { return std::get<T>(*this); };
|
|
/**
|
|
* @brief get result error
|
|
* @throw std::bad_variant_access
|
|
* @return result error if holded
|
|
*/
|
|
Error<ErrorEnum> error() const
|
|
{
|
|
return std::get<Error<ErrorEnum>>(*this);
|
|
};
|
|
/**
|
|
* @brief get result content
|
|
* @return result object content type
|
|
*/
|
|
Content type() const
|
|
{
|
|
switch (this->index()) {
|
|
case 0:
|
|
return Content::Value;
|
|
case 1:
|
|
return Content::Error;
|
|
case std::variant_npos:
|
|
default:
|
|
return Content::Empty;
|
|
};
|
|
};
|
|
/**
|
|
* @brief match result function
|
|
* @tparam UnaryFunctionValue
|
|
* function type which will be called if result contains value
|
|
* @tparam UnaryFunctionError
|
|
* function type which will be called if result contains error
|
|
* @param apply_value
|
|
* function which will be called if result contains value
|
|
* @param apply_error
|
|
* function which will be called if result contains error
|
|
*/
|
|
template <typename UnaryFunctionValue, typename UnaryFunctionError>
|
|
void match(UnaryFunctionValue apply_value,
|
|
UnaryFunctionError apply_error) const
|
|
{
|
|
switch (type()) {
|
|
case Content::Value:
|
|
apply_value(get());
|
|
break;
|
|
case Content::Error:
|
|
apply_error(error());
|
|
break;
|
|
case Content::Empty:
|
|
break;
|
|
}
|
|
};
|
|
/**
|
|
* @brief do action in case if no errors found
|
|
* @tparam U
|
|
* new value class name
|
|
* @tparam UnaryFunctionValue
|
|
* function type which will be cased if result contains value
|
|
* @param apply_value
|
|
* function which will be called if result contains value
|
|
* @return newly created result with another holded value type
|
|
*/
|
|
template <typename U, typename UnaryFunctionValue>
|
|
Result<U, ErrorEnum> onSuccess(UnaryFunctionValue apply_value) const
|
|
{
|
|
Result<U, ErrorEnum> result;
|
|
match([&result, &apply_value](T value) { result = apply_value(value); },
|
|
[&result](Error<ErrorEnum> error) { result = error; });
|
|
|
|
return result;
|
|
}
|
|
/**
|
|
* @brief recover to T in case of error
|
|
* @tparam UnaryFunctionError
|
|
* function type which will be cased if result contains error
|
|
* @param apply_error
|
|
* function which will be cased if result contains error
|
|
* @return value in case of Result::Content::Value, function call result
|
|
* otherwise
|
|
*/
|
|
template <typename UnaryFunctionError>
|
|
Result<T, ErrorEnum> recover(UnaryFunctionError apply_error) const
|
|
{
|
|
Result<T, ErrorEnum> val;
|
|
match([&val](T value) { val = value; },
|
|
[&val, &apply_error](Error<ErrorEnum> error) {
|
|
val = apply_error(error);
|
|
});
|
|
|
|
return val;
|
|
}
|
|
};
|
|
|
|
// additional functions
|
|
/**
|
|
* @brief match result function
|
|
* @tparam T
|
|
* value class name
|
|
* @tparam ErrorEnum
|
|
* error code enumeration
|
|
* @tparam UnaryFunctionValue
|
|
* function type which will be called if result contains value
|
|
* @tparam UnaryFunctionError
|
|
* function type which will be called if result contains error
|
|
* @param result
|
|
* result object
|
|
* @param apply_value
|
|
* function which will be called if result contains value
|
|
* @param apply_error
|
|
* function which will be called if result contains error
|
|
*/
|
|
template <typename T, typename ErrorEnum, typename UnaryFunctionValue,
|
|
typename UnaryFunctionError>
|
|
void match(const Result<T, ErrorEnum> &result, UnaryFunctionValue apply_value,
|
|
UnaryFunctionError apply_error)
|
|
{
|
|
return result.match(apply_value, apply_error);
|
|
};
|
|
}; // namespace Result
|
|
|
|
#endif /* _RESULT_HPP_ */
|