libcarla/include/carla/rpc/Response.h
2024-10-18 13:19:59 +08:00

151 lines
3.0 KiB
C++

// Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma
// de Barcelona (UAB).
//
// This work is licensed under the terms of the MIT license.
// For a copy, see <https://opensource.org/licenses/MIT>.
#pragma once
#include "carla/MsgPack.h"
#include "carla/MsgPackAdaptors.h"
#include <boost/optional.hpp>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable:4583)
#pragma warning(disable:4582)
#include <boost/variant2/variant.hpp>
#pragma warning(pop)
#else
#include <boost/variant2/variant.hpp>
#endif
#include <string>
namespace carla {
namespace rpc {
class ResponseError {
public:
ResponseError() = default;
explicit ResponseError(std::string message)
: _what(std::move(message)) {}
const std::string &What() const {
return _what;
}
MSGPACK_DEFINE_ARRAY(_what)
private:
/// @todo Needs initialization, empty strings end up calling memcpy on a
/// nullptr. Possibly a bug in MsgPack but could also be our specialization
/// for variants
std::string _what{"unknown error"};
};
template <typename T>
class Response {
public:
using value_type = T;
using error_type = ResponseError;
Response() = default;
template <typename TValue>
Response(TValue &&value) : _data(std::forward<TValue>(value)) {}
template <typename TValue>
void Reset(TValue &&value) {
_data = std::forward<TValue>(value);
}
bool HasError() const {
return _data.index() == 0;
}
template <typename... Ts>
void SetError(Ts &&... args) {
_data = error_type(std::forward<Ts>(args)...);
}
const error_type &GetError() const {
DEBUG_ASSERT(HasError());
return boost::variant2::get<error_type>(_data);
}
value_type &Get() {
DEBUG_ASSERT(!HasError());
return boost::variant2::get<value_type>(_data);
}
const value_type &Get() const {
DEBUG_ASSERT(!HasError());
return boost::variant2::get<value_type>(_data);
}
operator bool() const {
return !HasError();
}
MSGPACK_DEFINE_ARRAY(_data)
private:
boost::variant2::variant<error_type, value_type> _data;
};
template <>
class Response<void> {
public:
using value_type = void;
using error_type = ResponseError;
static Response Success() {
return success_flag{};
}
Response() : _data(error_type{}) {}
Response(ResponseError error) : _data(std::move(error)) {}
bool HasError() const {
return _data.has_value();
}
template <typename... Ts>
void SetError(Ts &&... args) {
_data = error_type(std::forward<Ts>(args)...);
}
const error_type &GetError() const {
DEBUG_ASSERT(HasError());
return *_data;
}
operator bool() const {
return !HasError();
}
MSGPACK_DEFINE_ARRAY(_data)
private:
struct success_flag {};
Response(success_flag) {}
boost::optional<error_type> _data;
};
} // namespace rpc
} // namespace carla