mirror of
https://github.com/vdemydiuk/mtapi.git
synced 2026-08-10 01:11:04 +00:00
Added thirdparty: boost library
This commit is contained in:
+220
@@ -0,0 +1,220 @@
|
||||
/* Copyright (c) 2018-2023 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#include <boost/redis/resp3/parser.hpp>
|
||||
#include <boost/redis/error.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <charconv>
|
||||
#include <limits>
|
||||
|
||||
namespace boost::redis::resp3 {
|
||||
|
||||
void to_int(int_type& i, std::string_view sv, system::error_code& ec)
|
||||
{
|
||||
auto const res = std::from_chars(sv.data(), sv.data() + std::size(sv), i);
|
||||
if (res.ec != std::errc())
|
||||
ec = error::not_a_number;
|
||||
}
|
||||
|
||||
parser::parser()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void parser::reset()
|
||||
{
|
||||
depth_ = 0;
|
||||
sizes_ = {{1}};
|
||||
bulk_length_ = (std::numeric_limits<unsigned long>::max)();
|
||||
bulk_ = type::invalid;
|
||||
consumed_ = 0;
|
||||
sizes_[0] = 2; // The sentinel must be more than 1.
|
||||
}
|
||||
|
||||
std::size_t
|
||||
parser::get_suggested_buffer_growth(std::size_t hint) const noexcept
|
||||
{
|
||||
if (!bulk_expected())
|
||||
return hint;
|
||||
|
||||
if (hint < bulk_length_ + 2)
|
||||
return bulk_length_ + 2;
|
||||
|
||||
return hint;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
parser::get_consumed() const noexcept
|
||||
{
|
||||
return consumed_;
|
||||
}
|
||||
|
||||
bool
|
||||
parser::done() const noexcept
|
||||
{
|
||||
return depth_ == 0 && bulk_ == type::invalid && consumed_ != 0;
|
||||
}
|
||||
|
||||
void
|
||||
parser::commit_elem() noexcept
|
||||
{
|
||||
--sizes_[depth_];
|
||||
while (sizes_[depth_] == 0) {
|
||||
--depth_;
|
||||
--sizes_[depth_];
|
||||
}
|
||||
}
|
||||
|
||||
auto
|
||||
parser::consume(std::string_view view, system::error_code& ec) noexcept -> parser::result
|
||||
{
|
||||
switch (bulk_) {
|
||||
case type::invalid:
|
||||
{
|
||||
auto const pos = view.find(sep, consumed_);
|
||||
if (pos == std::string::npos)
|
||||
return {}; // Needs more data to proceeed.
|
||||
|
||||
auto const t = to_type(view.at(consumed_));
|
||||
auto const content = view.substr(consumed_ + 1, pos - 1 - consumed_);
|
||||
auto const ret = consume_impl(t, content, ec);
|
||||
if (ec)
|
||||
return {};
|
||||
|
||||
consumed_ = pos + 2;
|
||||
if (!bulk_expected())
|
||||
return ret;
|
||||
|
||||
} [[fallthrough]];
|
||||
|
||||
default: // Handles bulk.
|
||||
{
|
||||
auto const span = bulk_length_ + 2;
|
||||
if ((std::size(view) - consumed_) < span)
|
||||
return {}; // Needs more data to proceeed.
|
||||
|
||||
auto const bulk_view = view.substr(consumed_, bulk_length_);
|
||||
node_type const ret = {bulk_, 1, depth_, bulk_view};
|
||||
bulk_ = type::invalid;
|
||||
commit_elem();
|
||||
|
||||
consumed_ += span;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto
|
||||
parser::consume_impl(
|
||||
type t,
|
||||
std::string_view elem,
|
||||
system::error_code& ec) -> parser::node_type
|
||||
{
|
||||
BOOST_ASSERT(!bulk_expected());
|
||||
|
||||
node_type ret;
|
||||
switch (t) {
|
||||
case type::streamed_string_part:
|
||||
{
|
||||
to_int(bulk_length_ , elem, ec);
|
||||
if (ec)
|
||||
return {};
|
||||
|
||||
if (bulk_length_ == 0) {
|
||||
ret = {type::streamed_string_part, 1, depth_, {}};
|
||||
sizes_[depth_] = 1; // We are done.
|
||||
bulk_ = type::invalid;
|
||||
commit_elem();
|
||||
} else {
|
||||
bulk_ = type::streamed_string_part;
|
||||
}
|
||||
} break;
|
||||
case type::blob_error:
|
||||
case type::verbatim_string:
|
||||
case type::blob_string:
|
||||
{
|
||||
if (elem.at(0) == '?') {
|
||||
// NOTE: This can only be triggered with blob_string.
|
||||
// Trick: A streamed string is read as an aggregate of
|
||||
// infinite length. When the streaming is done the server
|
||||
// is supposed to send a part with length 0.
|
||||
sizes_[++depth_] = (std::numeric_limits<std::size_t>::max)();
|
||||
ret = {type::streamed_string, 0, depth_, {}};
|
||||
} else {
|
||||
to_int(bulk_length_ , elem , ec);
|
||||
if (ec)
|
||||
return {};
|
||||
|
||||
bulk_ = t;
|
||||
}
|
||||
} break;
|
||||
case type::boolean:
|
||||
{
|
||||
if (std::empty(elem)) {
|
||||
ec = error::empty_field;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (elem.at(0) != 'f' && elem.at(0) != 't') {
|
||||
ec = error::unexpected_bool_value;
|
||||
return {};
|
||||
}
|
||||
|
||||
ret = {t, 1, depth_, elem};
|
||||
commit_elem();
|
||||
} break;
|
||||
case type::doublean:
|
||||
case type::big_number:
|
||||
case type::number:
|
||||
{
|
||||
if (std::empty(elem)) {
|
||||
ec = error::empty_field;
|
||||
return {};
|
||||
}
|
||||
} [[fallthrough]];
|
||||
case type::simple_error:
|
||||
case type::simple_string:
|
||||
case type::null:
|
||||
{
|
||||
ret = {t, 1, depth_, elem};
|
||||
commit_elem();
|
||||
} break;
|
||||
case type::push:
|
||||
case type::set:
|
||||
case type::array:
|
||||
case type::attribute:
|
||||
case type::map:
|
||||
{
|
||||
int_type l = -1;
|
||||
to_int(l, elem, ec);
|
||||
if (ec)
|
||||
return {};
|
||||
|
||||
ret = {t, l, depth_, {}};
|
||||
if (l == 0) {
|
||||
commit_elem();
|
||||
} else {
|
||||
if (depth_ == max_embedded_depth) {
|
||||
ec = error::exceeeds_max_nested_depth;
|
||||
return {};
|
||||
}
|
||||
|
||||
++depth_;
|
||||
|
||||
sizes_[depth_] = l * element_multiplicity(t);
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
{
|
||||
ec = error::invalid_data_type;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
} // boost::redis::resp3
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/* Copyright (c) 2018-2023 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#include <boost/redis/resp3/serialization.hpp>
|
||||
#include <boost/redis/resp3/parser.hpp>
|
||||
|
||||
namespace boost::redis::resp3 {
|
||||
|
||||
void boost_redis_to_bulk(std::string& payload, std::string_view data)
|
||||
{
|
||||
auto const str = std::to_string(data.size());
|
||||
|
||||
payload += to_code(type::blob_string);
|
||||
payload.append(std::cbegin(str), std::cend(str));
|
||||
payload += parser::sep;
|
||||
payload.append(std::cbegin(data), std::cend(data));
|
||||
payload += parser::sep;
|
||||
}
|
||||
|
||||
void add_header(std::string& payload, type t, std::size_t size)
|
||||
{
|
||||
auto const str = std::to_string(size);
|
||||
|
||||
payload += to_code(t);
|
||||
payload.append(std::cbegin(str), std::cend(str));
|
||||
payload += parser::sep;
|
||||
}
|
||||
|
||||
void add_blob(std::string& payload, std::string_view blob)
|
||||
{
|
||||
payload.append(std::cbegin(blob), std::cend(blob));
|
||||
payload += parser::sep;
|
||||
}
|
||||
|
||||
void add_separator(std::string& payload)
|
||||
{
|
||||
payload += parser::sep;
|
||||
}
|
||||
} // boost::redis::resp3
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/* Copyright (c) 2018-2023 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#include <boost/redis/resp3/type.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace boost::redis::resp3 {
|
||||
|
||||
auto to_string(type t) noexcept -> char const*
|
||||
{
|
||||
switch (t) {
|
||||
case type::array: return "array";
|
||||
case type::push: return "push";
|
||||
case type::set: return "set";
|
||||
case type::map: return "map";
|
||||
case type::attribute: return "attribute";
|
||||
case type::simple_string: return "simple_string";
|
||||
case type::simple_error: return "simple_error";
|
||||
case type::number: return "number";
|
||||
case type::doublean: return "doublean";
|
||||
case type::boolean: return "boolean";
|
||||
case type::big_number: return "big_number";
|
||||
case type::null: return "null";
|
||||
case type::blob_error: return "blob_error";
|
||||
case type::verbatim_string: return "verbatim_string";
|
||||
case type::blob_string: return "blob_string";
|
||||
case type::streamed_string: return "streamed_string";
|
||||
case type::streamed_string_part: return "streamed_string_part";
|
||||
default: return "invalid";
|
||||
}
|
||||
}
|
||||
|
||||
auto operator<<(std::ostream& os, type t) -> std::ostream&
|
||||
{
|
||||
os << to_string(t);
|
||||
return os;
|
||||
}
|
||||
|
||||
} // boost::redis::resp3
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/* Copyright (c) 2018-2023 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REDIS_RESP3_NODE_HPP
|
||||
#define BOOST_REDIS_RESP3_NODE_HPP
|
||||
|
||||
#include <boost/redis/resp3/type.hpp>
|
||||
|
||||
namespace boost::redis::resp3 {
|
||||
|
||||
/** \brief A node in the response tree.
|
||||
* \ingroup high-level-api
|
||||
*
|
||||
* RESP3 can contain recursive data structures: A map of sets of
|
||||
* vector of etc. As it is parsed each element is passed to user
|
||||
* callbacks (push parser). The signature of this
|
||||
* callback is `f(resp3::node<std::string_view)`. This class is called a node
|
||||
* because it can be seen as the element of the response tree. It
|
||||
* is a template so that users can use it with owing strings e.g.
|
||||
* `std::string` or `boost::static_string` etc.
|
||||
*
|
||||
* @tparam String A `std::string`-like type.
|
||||
*/
|
||||
template <class String>
|
||||
struct basic_node {
|
||||
/// The RESP3 type of the data in this node.
|
||||
type data_type = type::invalid;
|
||||
|
||||
/// The number of elements of an aggregate.
|
||||
std::size_t aggregate_size{};
|
||||
|
||||
/// The depth of this node in the response tree.
|
||||
std::size_t depth{};
|
||||
|
||||
/// The actual data. For aggregate types this is usually empty.
|
||||
String value{};
|
||||
};
|
||||
|
||||
/** @brief Compares a node for equality.
|
||||
* @relates basic_node
|
||||
*
|
||||
* @param a Left hand side node object.
|
||||
* @param b Right hand side node object.
|
||||
*/
|
||||
template <class String>
|
||||
auto operator==(basic_node<String> const& a, basic_node<String> const& b)
|
||||
{
|
||||
return a.aggregate_size == b.aggregate_size
|
||||
&& a.depth == b.depth
|
||||
&& a.data_type == b.data_type
|
||||
&& a.value == b.value;
|
||||
};
|
||||
|
||||
/** @brief A node in the response tree.
|
||||
* @ingroup high-level-api
|
||||
*/
|
||||
using node = basic_node<std::string>;
|
||||
|
||||
} // boost::redis::resp3
|
||||
|
||||
#endif // BOOST_REDIS_RESP3_NODE_HPP
|
||||
+106
@@ -0,0 +1,106 @@
|
||||
/* Copyright (c) 2018-2023 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REDIS_RESP3_PARSER_HPP
|
||||
#define BOOST_REDIS_RESP3_PARSER_HPP
|
||||
|
||||
#include <boost/redis/resp3/node.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
|
||||
namespace boost::redis::resp3 {
|
||||
|
||||
using int_type = std::uint64_t;
|
||||
|
||||
class parser {
|
||||
public:
|
||||
using node_type = basic_node<std::string_view>;
|
||||
using result = std::optional<node_type>;
|
||||
|
||||
static constexpr std::size_t max_embedded_depth = 5;
|
||||
static constexpr std::string_view sep = "\r\n";
|
||||
|
||||
private:
|
||||
// The current depth. Simple data types will have depth 0, whereas
|
||||
// the elements of aggregates will have depth 1. Embedded types
|
||||
// will have increasing depth.
|
||||
std::size_t depth_;
|
||||
|
||||
// The parser supports up to 5 levels of nested structures. The
|
||||
// first element in the sizes stack is a sentinel and must be
|
||||
// different from 1.
|
||||
std::array<std::size_t, max_embedded_depth + 1> sizes_;
|
||||
|
||||
// Contains the length expected in the next bulk read.
|
||||
int_type bulk_length_;
|
||||
|
||||
// The type of the next bulk. Contains type::invalid if no bulk is
|
||||
// expected.
|
||||
type bulk_;
|
||||
|
||||
// The number of bytes consumed from the buffer.
|
||||
std::size_t consumed_;
|
||||
|
||||
// Returns the number of bytes that have been consumed.
|
||||
auto consume_impl(type t, std::string_view elem, system::error_code& ec) -> node_type;
|
||||
|
||||
void commit_elem() noexcept;
|
||||
|
||||
// The bulk type expected in the next read. If none is expected
|
||||
// returns type::invalid.
|
||||
[[nodiscard]]
|
||||
auto bulk_expected() const noexcept -> bool
|
||||
{ return bulk_ != type::invalid; }
|
||||
|
||||
public:
|
||||
parser();
|
||||
|
||||
// Returns true when the parser is done with the current message.
|
||||
[[nodiscard]]
|
||||
auto done() const noexcept -> bool;
|
||||
|
||||
auto get_suggested_buffer_growth(std::size_t hint) const noexcept -> std::size_t;
|
||||
|
||||
auto get_consumed() const noexcept -> std::size_t;
|
||||
|
||||
auto consume(std::string_view view, system::error_code& ec) noexcept -> result;
|
||||
|
||||
void reset();
|
||||
};
|
||||
|
||||
// Returns false if more data is needed. If true is returned the
|
||||
// parser is either done or an error occured, that can be checked on
|
||||
// ec.
|
||||
template <class Adapter>
|
||||
bool
|
||||
parse(
|
||||
resp3::parser& p,
|
||||
std::string_view const& msg,
|
||||
Adapter& adapter,
|
||||
system::error_code& ec)
|
||||
{
|
||||
while (!p.done()) {
|
||||
auto const res = p.consume(msg, ec);
|
||||
if (ec)
|
||||
return true;
|
||||
|
||||
if (!res)
|
||||
return false;
|
||||
|
||||
adapter(res.value(), ec);
|
||||
if (ec)
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // boost::redis::resp3
|
||||
|
||||
#endif // BOOST_REDIS_RESP3_PARSER_HPP
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
/* Copyright (c) 2018-2023 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REDIS_RESP3_SERIALIZATION_HPP
|
||||
#define BOOST_REDIS_RESP3_SERIALIZATION_HPP
|
||||
|
||||
#include <boost/redis/resp3/type.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/redis/resp3/parser.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
// NOTE: Consider detecting tuples in the type in the parameter pack
|
||||
// to calculate the header size correctly.
|
||||
|
||||
namespace boost::redis::resp3 {
|
||||
|
||||
/** @brief Adds a bulk to the request.
|
||||
* @relates boost::redis::request
|
||||
*
|
||||
* This function is useful in serialization of your own data
|
||||
* structures in a request. For example
|
||||
*
|
||||
* @code
|
||||
* void boost_redis_to_bulk(std::string& payload, mystruct const& obj)
|
||||
* {
|
||||
* auto const str = // Convert obj to a string.
|
||||
* boost_redis_to_bulk(payload, str);
|
||||
* }
|
||||
* @endcode
|
||||
*
|
||||
* @param payload Storage on which data will be copied into.
|
||||
* @param data Data that will be serialized and stored in `payload`.
|
||||
*
|
||||
* See more in @ref serialization.
|
||||
*/
|
||||
void boost_redis_to_bulk(std::string& payload, std::string_view data);
|
||||
|
||||
template <class T, typename = typename std::enable_if<std::is_integral<T>::value>::type>
|
||||
void boost_redis_to_bulk(std::string& payload, T n)
|
||||
{
|
||||
auto const s = std::to_string(n);
|
||||
boost::redis::resp3::boost_redis_to_bulk(payload, std::string_view{s});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
struct add_bulk_impl {
|
||||
static void add(std::string& payload, T const& from)
|
||||
{
|
||||
using namespace boost::redis::resp3;
|
||||
boost_redis_to_bulk(payload, from);
|
||||
}
|
||||
};
|
||||
|
||||
template <class ...Ts>
|
||||
struct add_bulk_impl<std::tuple<Ts...>> {
|
||||
static void add(std::string& payload, std::tuple<Ts...> const& t)
|
||||
{
|
||||
auto f = [&](auto const&... vs)
|
||||
{
|
||||
using namespace boost::redis::resp3;
|
||||
(boost_redis_to_bulk(payload, vs), ...);
|
||||
};
|
||||
|
||||
std::apply(f, t);
|
||||
}
|
||||
};
|
||||
|
||||
template <class U, class V>
|
||||
struct add_bulk_impl<std::pair<U, V>> {
|
||||
static void add(std::string& payload, std::pair<U, V> const& from)
|
||||
{
|
||||
using namespace boost::redis::resp3;
|
||||
boost_redis_to_bulk(payload, from.first);
|
||||
boost_redis_to_bulk(payload, from.second);
|
||||
}
|
||||
};
|
||||
|
||||
void add_header(std::string& payload, type t, std::size_t size);
|
||||
|
||||
template <class T>
|
||||
void add_bulk(std::string& payload, T const& data)
|
||||
{
|
||||
add_bulk_impl<T>::add(payload, data);
|
||||
}
|
||||
|
||||
template <class>
|
||||
struct bulk_counter;
|
||||
|
||||
template <class>
|
||||
struct bulk_counter {
|
||||
static constexpr auto size = 1U;
|
||||
};
|
||||
|
||||
template <class T, class U>
|
||||
struct bulk_counter<std::pair<T, U>> {
|
||||
static constexpr auto size = 2U;
|
||||
};
|
||||
|
||||
void add_blob(std::string& payload, std::string_view blob);
|
||||
void add_separator(std::string& payload);
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <class Adapter>
|
||||
void deserialize(std::string_view const& data, Adapter adapter, system::error_code& ec)
|
||||
{
|
||||
parser parser;
|
||||
while (!parser.done()) {
|
||||
auto const res = parser.consume(data, ec);
|
||||
if (ec)
|
||||
return;
|
||||
|
||||
BOOST_ASSERT(res.has_value());
|
||||
|
||||
adapter(res.value(), ec);
|
||||
if (ec)
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(parser.get_consumed() == std::size(data));
|
||||
}
|
||||
|
||||
template <class Adapter>
|
||||
void deserialize(std::string_view const& data, Adapter adapter)
|
||||
{
|
||||
system::error_code ec;
|
||||
deserialize(data, adapter, ec);
|
||||
|
||||
if (ec)
|
||||
BOOST_THROW_EXCEPTION(system::system_error{ec});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // boost::redis::resp3
|
||||
|
||||
#endif // BOOST_REDIS_RESP3_SERIALIZATION_HPP
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
/* Copyright (c) 2018-2023 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REDIS_RESP3_TYPE_HPP
|
||||
#define BOOST_REDIS_RESP3_TYPE_HPP
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace boost::redis::resp3 {
|
||||
|
||||
/** \brief RESP3 data types.
|
||||
\ingroup high-level-api
|
||||
|
||||
The RESP3 specification can be found at https://github.com/redis/redis-specifications/blob/master/protocol/RESP3.md.
|
||||
*/
|
||||
enum class type
|
||||
{ /// Aggregate
|
||||
array,
|
||||
/// Aaggregate
|
||||
push,
|
||||
/// Aggregate
|
||||
set,
|
||||
/// Aggregate
|
||||
map,
|
||||
/// Aggregate
|
||||
attribute,
|
||||
/// Simple
|
||||
simple_string,
|
||||
/// Simple
|
||||
simple_error,
|
||||
/// Simple
|
||||
number,
|
||||
/// Simple
|
||||
doublean,
|
||||
/// Simple
|
||||
boolean,
|
||||
/// Simple
|
||||
big_number,
|
||||
/// Simple
|
||||
null,
|
||||
/// Simple
|
||||
blob_error,
|
||||
/// Simple
|
||||
verbatim_string,
|
||||
/// Simple
|
||||
blob_string,
|
||||
/// Simple
|
||||
streamed_string,
|
||||
/// Simple
|
||||
streamed_string_part,
|
||||
/// Invalid
|
||||
invalid
|
||||
};
|
||||
|
||||
/** \brief Converts the data type to a string.
|
||||
* \ingroup high-level-api
|
||||
* \param t RESP3 type.
|
||||
*/
|
||||
auto to_string(type t) noexcept -> char const*;
|
||||
|
||||
/** \brief Writes the type to the output stream.
|
||||
* \ingroup high-level-api
|
||||
* \param os Output stream.
|
||||
* \param t RESP3 type.
|
||||
*/
|
||||
auto operator<<(std::ostream& os, type t) -> std::ostream&;
|
||||
|
||||
/* Checks whether the data type is an aggregate.
|
||||
*/
|
||||
constexpr auto is_aggregate(type t) noexcept -> bool
|
||||
{
|
||||
switch (t) {
|
||||
case type::array:
|
||||
case type::push:
|
||||
case type::set:
|
||||
case type::map:
|
||||
case type::attribute: return true;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
// For map and attribute data types this function returns 2. All
|
||||
// other types have value 1.
|
||||
constexpr auto element_multiplicity(type t) noexcept -> std::size_t
|
||||
{
|
||||
switch (t) {
|
||||
case type::map:
|
||||
case type::attribute: return 2ULL;
|
||||
default: return 1ULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the wire code of a given type.
|
||||
constexpr auto to_code(type t) noexcept -> char
|
||||
{
|
||||
switch (t) {
|
||||
case type::blob_error: return '!';
|
||||
case type::verbatim_string: return '=';
|
||||
case type::blob_string: return '$';
|
||||
case type::streamed_string_part: return ';';
|
||||
case type::simple_error: return '-';
|
||||
case type::number: return ':';
|
||||
case type::doublean: return ',';
|
||||
case type::boolean: return '#';
|
||||
case type::big_number: return '(';
|
||||
case type::simple_string: return '+';
|
||||
case type::null: return '_';
|
||||
case type::push: return '>';
|
||||
case type::set: return '~';
|
||||
case type::array: return '*';
|
||||
case type::attribute: return '|';
|
||||
case type::map: return '%';
|
||||
|
||||
default: BOOST_ASSERT(false); return ' ';
|
||||
}
|
||||
}
|
||||
|
||||
// Converts a wire-format RESP3 type (char) to a resp3 type.
|
||||
constexpr auto to_type(char c) noexcept -> type
|
||||
{
|
||||
switch (c) {
|
||||
case '!': return type::blob_error;
|
||||
case '=': return type::verbatim_string;
|
||||
case '$': return type::blob_string;
|
||||
case ';': return type::streamed_string_part;
|
||||
case '-': return type::simple_error;
|
||||
case ':': return type::number;
|
||||
case ',': return type::doublean;
|
||||
case '#': return type::boolean;
|
||||
case '(': return type::big_number;
|
||||
case '+': return type::simple_string;
|
||||
case '_': return type::null;
|
||||
case '>': return type::push;
|
||||
case '~': return type::set;
|
||||
case '*': return type::array;
|
||||
case '|': return type::attribute;
|
||||
case '%': return type::map;
|
||||
default: return type::invalid;
|
||||
}
|
||||
}
|
||||
|
||||
} // boost::redis::resp3
|
||||
|
||||
#endif // BOOST_REDIS_RESP3_TYPE_HPP
|
||||
Reference in New Issue
Block a user