mirror of https://gitee.com/bigwinds/arangodb
Forbid ambiguous casts to and from ResultT (#8147)
* Forbid ambiguous casts to and from ResultT * Reformat * Changed enabled_if checks to check for implicit casts to Result * Added comments
This commit is contained in:
parent
4fe2a412b7
commit
e3f5a88762
|
@ -23,6 +23,8 @@
|
||||||
#ifndef ARANGODB_BASICS_RESULT_T_H
|
#ifndef ARANGODB_BASICS_RESULT_T_H
|
||||||
#define ARANGODB_BASICS_RESULT_T_H
|
#define ARANGODB_BASICS_RESULT_T_H
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
|
|
||||||
#include "Basics/Common.h"
|
#include "Basics/Common.h"
|
||||||
|
@ -55,6 +57,7 @@ namespace arangodb {
|
||||||
// or, having a `Result result` with result.fail() being true,
|
// or, having a `Result result` with result.fail() being true,
|
||||||
// return result;
|
// return result;
|
||||||
// .
|
// .
|
||||||
|
// Some implicit conversions are disabled when they could cause ambiguity.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class ResultT {
|
class ResultT {
|
||||||
public:
|
public:
|
||||||
|
@ -74,22 +77,54 @@ class ResultT {
|
||||||
return ResultT(boost::none, errorNumber, errorMessage);
|
return ResultT(boost::none, errorNumber, errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are not explicit on purpose
|
ResultT static error(Result const& other) {
|
||||||
|
TRI_ASSERT(other.fail());
|
||||||
|
return ResultT(boost::none, other);
|
||||||
|
}
|
||||||
|
|
||||||
|
ResultT static error(Result&& other) {
|
||||||
|
TRI_ASSERT(other.fail());
|
||||||
|
return ResultT(boost::none, std::move(other));
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is disabled if U is implicitly convertible to Result
|
||||||
|
// (e.g., if U = int) to avoid ambiguous construction.
|
||||||
|
// Use ::success() or ::error() instead in that case.
|
||||||
|
template <typename U = T, typename = std::enable_if_t<!std::is_convertible<U, Result>::value>>
|
||||||
|
// This is not explicit on purpose
|
||||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
ResultT(Result const& other) : _result(other) {
|
ResultT(Result const& other) : _result(other) {
|
||||||
// .ok() is not allowed here, as _val should be expected to be initialized
|
// .ok() is not allowed here, as _val should be expected to be initialized
|
||||||
// iff .ok() is true.
|
// iff .ok() is true.
|
||||||
TRI_ASSERT(other.fail());
|
TRI_ASSERT(other.fail());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is disabled if U is implicitly convertible to Result
|
||||||
|
// (e.g., if U = int) to avoid ambiguous construction.
|
||||||
|
// Use ::success() or ::error() instead in that case.
|
||||||
|
template <typename U = T, typename = std::enable_if_t<!std::is_convertible<U, Result>::value>>
|
||||||
|
// This is not explicit on purpose
|
||||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
ResultT(Result&& other) : _result(std::move(other)) {
|
ResultT(Result&& other) : _result(std::move(other)) {
|
||||||
// .ok() is not allowed here, as _val should be expected to be initialized
|
// .ok() is not allowed here, as _val should be expected to be initialized
|
||||||
// iff .ok() is true.
|
// iff .ok() is true.
|
||||||
TRI_ASSERT(other.fail());
|
TRI_ASSERT(other.fail());
|
||||||
}
|
}
|
||||||
|
|
||||||
// These are not explicit on purpose
|
// This is disabled if U is implicitly convertible to Result
|
||||||
|
// (e.g., if U = int) to avoid ambiguous construction.
|
||||||
|
// Use ::success() or ::error() instead in that case.
|
||||||
|
template <typename U = T, typename = std::enable_if_t<!std::is_convertible<U, Result>::value>>
|
||||||
|
// This is not explicit on purpose
|
||||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
ResultT(T&& val) : ResultT(std::move(val), TRI_ERROR_NO_ERROR) {}
|
ResultT(T&& val) : ResultT(std::move(val), TRI_ERROR_NO_ERROR) {}
|
||||||
|
|
||||||
|
// This is disabled if U is implicitly convertible to Result
|
||||||
|
// (e.g., if U = int) to avoid ambiguous construction.
|
||||||
|
// Use ::success() or ::error() instead in that case.
|
||||||
|
template <typename U = T, typename = std::enable_if_t<!std::is_convertible<U, Result>::value>>
|
||||||
|
// This is not explicit on purpose
|
||||||
|
// NOLINTNEXTLINE(google-explicit-constructor)
|
||||||
ResultT(T const& val) : ResultT(val, TRI_ERROR_NO_ERROR) {}
|
ResultT(T const& val) : ResultT(val, TRI_ERROR_NO_ERROR) {}
|
||||||
|
|
||||||
ResultT() = delete;
|
ResultT() = delete;
|
||||||
|
@ -104,8 +139,6 @@ class ResultT {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result copy_result() const { return *this; }
|
|
||||||
|
|
||||||
// These would be very convenient, but also make it very easy to accidentally
|
// These would be very convenient, but also make it very easy to accidentally
|
||||||
// use the value of an error-result. So don't add them.
|
// use the value of an error-result. So don't add them.
|
||||||
//
|
//
|
||||||
|
@ -124,7 +157,17 @@ class ResultT {
|
||||||
|
|
||||||
T const&& operator*() const&& { return get(); }
|
T const&& operator*() const&& { return get(); }
|
||||||
|
|
||||||
explicit operator bool() const { return ok(); }
|
// Allow convenient check to allow for code like
|
||||||
|
// if (res) { /* use res.get() */ } else { /* handle error res.result() */ }
|
||||||
|
// . Is disabled for bools to avoid accidental confusion of
|
||||||
|
// if (res)
|
||||||
|
// with
|
||||||
|
// if (res.get())
|
||||||
|
// .
|
||||||
|
template <typename U = T, typename = std::enable_if_t<!std::is_same<U, bool>::value>>
|
||||||
|
explicit operator bool() const {
|
||||||
|
return ok();
|
||||||
|
}
|
||||||
|
|
||||||
T const& get() const { return _val.get(); }
|
T const& get() const { return _val.get(); }
|
||||||
|
|
||||||
|
@ -163,7 +206,7 @@ class ResultT {
|
||||||
// forwarded methods
|
// forwarded methods
|
||||||
bool ok() const { return _result.ok(); }
|
bool ok() const { return _result.ok(); }
|
||||||
bool fail() const { return _result.fail(); }
|
bool fail() const { return _result.fail(); }
|
||||||
bool is(uint64_t code) { return _result.is(code); }
|
bool is(int code) { return _result.is(code); }
|
||||||
int errorNumber() const { return _result.errorNumber(); }
|
int errorNumber() const { return _result.errorNumber(); }
|
||||||
std::string errorMessage() const { return _result.errorMessage(); }
|
std::string errorMessage() const { return _result.errorMessage(); }
|
||||||
|
|
||||||
|
@ -186,6 +229,12 @@ class ResultT {
|
||||||
|
|
||||||
ResultT(boost::optional<T> const& val_, int errorNumber, std::string const& errorMessage)
|
ResultT(boost::optional<T> const& val_, int errorNumber, std::string const& errorMessage)
|
||||||
: _result(errorNumber, errorMessage), _val(val_) {}
|
: _result(errorNumber, errorMessage), _val(val_) {}
|
||||||
|
|
||||||
|
ResultT(boost::optional<T>&& val_, Result result)
|
||||||
|
: _result(std::move(result)), _val(std::move(val_)) {}
|
||||||
|
|
||||||
|
ResultT(boost::optional<T>&& val_, Result&& result)
|
||||||
|
: _result(std::move(result)), _val(std::move(val_)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace arangodb
|
} // namespace arangodb
|
||||||
|
|
|
@ -290,7 +290,7 @@ ResultT<bool> RestRepairHandler::jobFinished(std::string const& jobId) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JobStatus::finished:
|
case JobStatus::finished:
|
||||||
return true;
|
return ResultT<bool>::success(true);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case JobStatus::failed:
|
case JobStatus::failed:
|
||||||
|
@ -298,14 +298,14 @@ ResultT<bool> RestRepairHandler::jobFinished(std::string const& jobId) {
|
||||||
<< "RestRepairHandler::jobFinished: "
|
<< "RestRepairHandler::jobFinished: "
|
||||||
<< "Job " << jobId << " failed, aborting";
|
<< "Job " << jobId << " failed, aborting";
|
||||||
|
|
||||||
return Result(TRI_ERROR_CLUSTER_REPAIRS_JOB_FAILED);
|
return ResultT<bool>::error(TRI_ERROR_CLUSTER_REPAIRS_JOB_FAILED);
|
||||||
|
|
||||||
case JobStatus::missing:
|
case JobStatus::missing:
|
||||||
LOG_TOPIC(ERR, arangodb::Logger::CLUSTER)
|
LOG_TOPIC(ERR, arangodb::Logger::CLUSTER)
|
||||||
<< "RestRepairHandler::jobFinished: "
|
<< "RestRepairHandler::jobFinished: "
|
||||||
<< "Job " << jobId << " went missing, aborting";
|
<< "Job " << jobId << " went missing, aborting";
|
||||||
|
|
||||||
return Result(TRI_ERROR_CLUSTER_REPAIRS_JOB_DISAPPEARED);
|
return ResultT<bool>::error(TRI_ERROR_CLUSTER_REPAIRS_JOB_DISAPPEARED);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -314,10 +314,10 @@ ResultT<bool> RestRepairHandler::jobFinished(std::string const& jobId) {
|
||||||
<< "Failed to get job status: "
|
<< "Failed to get job status: "
|
||||||
<< "[" << jobStatus.errorNumber() << "] " << jobStatus.errorMessage();
|
<< "[" << jobStatus.errorNumber() << "] " << jobStatus.errorMessage();
|
||||||
|
|
||||||
return std::move(std::move(jobStatus).result());
|
return ResultT<bool>::error(std::move(jobStatus.result()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return ResultT<bool>::success(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Result RestRepairHandler::executeRepairOperations(DatabaseID const& databaseId,
|
Result RestRepairHandler::executeRepairOperations(DatabaseID const& databaseId,
|
||||||
|
@ -636,7 +636,7 @@ ResultT<bool> RestRepairHandler::checkReplicationFactor(DatabaseID const& databa
|
||||||
<< "No ClusterInfo instance";
|
<< "No ClusterInfo instance";
|
||||||
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_HTTP_SERVER_ERROR);
|
generateError(rest::ResponseCode::SERVER_ERROR, TRI_ERROR_HTTP_SERVER_ERROR);
|
||||||
|
|
||||||
return Result(TRI_ERROR_INTERNAL);
|
return ResultT<bool>::error(TRI_ERROR_INTERNAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
clusterInfo->loadPlan();
|
clusterInfo->loadPlan();
|
||||||
|
@ -656,11 +656,11 @@ ResultT<bool> RestRepairHandler::checkReplicationFactor(DatabaseID const& databa
|
||||||
<< "replicationFactor is " << collection->replicationFactor()
|
<< "replicationFactor is " << collection->replicationFactor()
|
||||||
<< ", but the shard has " << dbServers.size() << " DBServers.";
|
<< ", but the shard has " << dbServers.size() << " DBServers.";
|
||||||
|
|
||||||
return false;
|
return ResultT<bool>::success(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return ResultT<bool>::success(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RestRepairHandler::generateResult(rest::ResponseCode code,
|
void RestRepairHandler::generateResult(rest::ResponseCode code,
|
||||||
|
|
Loading…
Reference in New Issue