mirror of
https://github.com/boostorg/redis.git
synced 2026-01-19 04:42:09 +00:00
Removes json serialization boilerplate.
This commit is contained in:
@@ -134,13 +134,13 @@ if (MSVC)
|
||||
target_compile_definitions(cpp20_resolve_with_sentinel PRIVATE _WIN32_WINNT=0x0601)
|
||||
endif()
|
||||
|
||||
add_executable(cpp20_serialization examples/cpp20_serialization.cpp)
|
||||
target_compile_features(cpp20_serialization PUBLIC cxx_std_20)
|
||||
target_link_libraries(cpp20_serialization common)
|
||||
add_test(cpp20_serialization cpp20_serialization)
|
||||
add_executable(cpp20_json_serialization examples/cpp20_json_serialization.cpp)
|
||||
target_compile_features(cpp20_json_serialization PUBLIC cxx_std_20)
|
||||
target_link_libraries(cpp20_json_serialization common)
|
||||
add_test(cpp20_json_serialization cpp20_json_serialization)
|
||||
if (MSVC)
|
||||
target_compile_options(cpp20_serialization PRIVATE /bigobj)
|
||||
target_compile_definitions(cpp20_serialization PRIVATE _WIN32_WINNT=0x0601)
|
||||
target_compile_options(cpp20_json_serialization PRIVATE /bigobj)
|
||||
target_compile_definitions(cpp20_json_serialization PRIVATE _WIN32_WINNT=0x0601)
|
||||
endif()
|
||||
|
||||
add_executable(cpp20_subscriber examples/cpp20_subscriber.cpp)
|
||||
|
||||
@@ -881,6 +881,7 @@ Acknowledgement to people that helped shape Boost.Redis
|
||||
next. Now requests are continuously coalesced and written to the
|
||||
socket. This made the request::coalesce unnecessary and threfore it
|
||||
was removed.
|
||||
* Native json support for Boost.Describe'd classes.
|
||||
|
||||
### v1.4.0-1
|
||||
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
/* Copyright (c) 2018-2022 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#define BOOST_JSON_NO_LIB
|
||||
#define BOOST_CONTAINER_NO_LIB
|
||||
#include <boost/redis.hpp>
|
||||
#include <boost/describe.hpp>
|
||||
#include <boost/mp11.hpp>
|
||||
#include <boost/json.hpp>
|
||||
|
||||
using namespace boost::describe;
|
||||
using namespace boost::json;
|
||||
|
||||
template <
|
||||
class T,
|
||||
class Bd = describe_bases<T, mod_any_access>,
|
||||
class Md = describe_members<T, mod_any_access>,
|
||||
class En = std::enable_if_t<!std::is_union<T>::value>
|
||||
>
|
||||
std::ostream& operator<<(std::ostream& os, T const & t)
|
||||
{
|
||||
os << "{";
|
||||
|
||||
bool first = true;
|
||||
|
||||
boost::mp11::mp_for_each<Bd>([&](auto D){
|
||||
|
||||
if( !first ) { os << ", "; } first = false;
|
||||
|
||||
using B = typename decltype(D)::type;
|
||||
os << (B const&)t;
|
||||
|
||||
});
|
||||
|
||||
boost::mp11::mp_for_each<Md>([&](auto D){
|
||||
|
||||
if( !first ) { os << ", "; } first = false;
|
||||
|
||||
os << "." << D.name << " = " << t.*D.pointer;
|
||||
|
||||
});
|
||||
|
||||
os << "}";
|
||||
return os;
|
||||
}
|
||||
|
||||
template <
|
||||
class T,
|
||||
class D1 = boost::describe::describe_members<T, boost::describe::mod_public | boost::describe::mod_protected>,
|
||||
class D2 = boost::describe::describe_members<T, boost::describe::mod_private>,
|
||||
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value && !std::is_union<T>::value>
|
||||
>
|
||||
void tag_invoke(boost::json::value_from_tag const&, boost::json::value& v, T const & t)
|
||||
{
|
||||
auto& obj = v.emplace_object();
|
||||
|
||||
boost::mp11::mp_for_each<D1>([&](auto D){
|
||||
|
||||
obj[ D.name ] = boost::json::value_from( t.*D.pointer );
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
template<class T> void extract( boost::json::object const & obj, char const * name, T & value )
|
||||
{
|
||||
value = boost::json::value_to<T>( obj.at( name ) );
|
||||
}
|
||||
|
||||
template<class T,
|
||||
class D1 = boost::describe::describe_members<T,
|
||||
boost::describe::mod_public | boost::describe::mod_protected>,
|
||||
class D2 = boost::describe::describe_members<T, boost::describe::mod_private>,
|
||||
class En = std::enable_if_t<boost::mp11::mp_empty<D2>::value && !std::is_union<T>::value> >
|
||||
|
||||
T tag_invoke( boost::json::value_to_tag<T> const&, boost::json::value const& v )
|
||||
{
|
||||
auto const& obj = v.as_object();
|
||||
|
||||
T t{};
|
||||
|
||||
boost::mp11::mp_for_each<D1>([&](auto D){
|
||||
|
||||
extract( obj, D.name, t.*D.pointer );
|
||||
|
||||
});
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
// Serialization
|
||||
template <class T>
|
||||
void boost_redis_to_bulk(std::string& to, T const& u)
|
||||
{
|
||||
boost::redis::resp3::boost_redis_to_bulk(to, serialize(value_from(u)));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void boost_redis_from_bulk(T& u, std::string_view sv, boost::system::error_code&)
|
||||
{
|
||||
value jv = parse(sv);
|
||||
u = value_to<T>(jv);
|
||||
}
|
||||
@@ -6,22 +6,26 @@
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#if defined(BOOST_ASIO_HAS_CO_AWAIT)
|
||||
#define BOOST_JSON_NO_LIB
|
||||
#define BOOST_CONTAINER_NO_LIB
|
||||
#include <boost/redis.hpp>
|
||||
#include <iostream>
|
||||
#include <boost/describe.hpp>
|
||||
#include <boost/redis/json.hpp>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include "common/common.hpp"
|
||||
#include "common/serialization.hpp"
|
||||
|
||||
// Include this in no more than one .cpp file.
|
||||
#include <boost/json/src.hpp>
|
||||
|
||||
namespace net = boost::asio;
|
||||
namespace redis = boost::redis;
|
||||
using namespace boost::describe;
|
||||
using boost::redis::request;
|
||||
using boost::redis::response;
|
||||
using boost::redis::ignore_t;
|
||||
using boost::redis::operation;
|
||||
using boost::redis::ignore_t;
|
||||
|
||||
struct user {
|
||||
std::string name;
|
||||
@@ -41,46 +45,34 @@ auto run(std::shared_ptr<connection> conn, std::string host, std::string port) -
|
||||
co_await conn->async_run();
|
||||
}
|
||||
|
||||
auto hello(std::shared_ptr<connection> conn) -> net::awaitable<void>
|
||||
{
|
||||
request req;
|
||||
req.push("HELLO", 3);
|
||||
|
||||
co_await conn->async_exec(req);
|
||||
}
|
||||
|
||||
auto sadd(std::shared_ptr<connection> conn) -> net::awaitable<void>
|
||||
{
|
||||
std::set<user> users
|
||||
{{"Joao", "58", "Brazil"} , {"Serge", "60", "France"}};
|
||||
|
||||
request req;
|
||||
req.push_range("SADD", "sadd-key", users); // Sends
|
||||
|
||||
co_await conn->async_exec(req);
|
||||
}
|
||||
|
||||
auto smembers(std::shared_ptr<connection> conn) -> net::awaitable<void>
|
||||
{
|
||||
request req;
|
||||
req.push("SMEMBERS", "sadd-key");
|
||||
|
||||
response<std::set<user>> resp;
|
||||
|
||||
co_await conn->async_exec(req, resp);
|
||||
|
||||
for (auto const& e: std::get<0>(resp).value())
|
||||
std::cout << e << "\n";
|
||||
}
|
||||
|
||||
net::awaitable<void> co_main(std::string host, std::string port)
|
||||
{
|
||||
auto ex = co_await net::this_coro::executor;
|
||||
auto conn = std::make_shared<connection>(ex);
|
||||
net::co_spawn(ex, run(conn, host, port), net::detached);
|
||||
co_await hello(conn);
|
||||
co_await sadd(conn);
|
||||
co_await smembers(conn);
|
||||
|
||||
// A set of users that will be automatically serialized to json.
|
||||
std::set<user> users
|
||||
{{"Joao", "58", "Brazil"} , {"Serge", "60", "France"}};
|
||||
|
||||
// To simplify we send the set and retrieve it in the same
|
||||
// resquest.
|
||||
request req;
|
||||
req.push("HELLO", 3);
|
||||
req.push_range("SADD", "sadd-key", users);
|
||||
req.push("SMEMBERS", "sadd-key");
|
||||
|
||||
// The response will contain the deserialized set, which should
|
||||
// match the one we sent.
|
||||
response<ignore_t, ignore_t, std::set<user>> resp;
|
||||
|
||||
// Sends the request and receives the response.
|
||||
co_await conn->async_exec(req, resp);
|
||||
|
||||
// Print.
|
||||
for (auto const& e: std::get<2>(resp).value())
|
||||
std::cout << e.name << " " << e.age << " " << e.country << "\n";
|
||||
|
||||
conn->cancel(operation::run);
|
||||
}
|
||||
|
||||
34
include/boost/redis/json.hpp
Normal file
34
include/boost/redis/json.hpp
Normal file
@@ -0,0 +1,34 @@
|
||||
/* Copyright (c) 2018-2022 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
#ifndef BOOST_REDIS_JSON_HPP
|
||||
#define BOOST_REDIS_JSON_HPP
|
||||
|
||||
#include <boost/json.hpp>
|
||||
#include <boost/redis/resp3/serialization.hpp>
|
||||
|
||||
namespace boost::redis::json
|
||||
{
|
||||
|
||||
template <class T>
|
||||
void boost_redis_to_bulk(std::string& to, T const& u)
|
||||
{
|
||||
redis::resp3::boost_redis_to_bulk(to, boost::json::serialize(boost::json::value_from(u)));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void boost_redis_from_bulk(T& u, std::string_view sv, system::error_code&)
|
||||
{
|
||||
auto const jv = boost::json::parse(sv);
|
||||
u = boost::json::value_to<T>(jv);
|
||||
}
|
||||
|
||||
} // boost::redis::json
|
||||
|
||||
using boost::redis::json::boost_redis_to_bulk;
|
||||
using boost::redis::json::boost_redis_from_bulk;
|
||||
|
||||
#endif // BOOST_REDIS_JSON_HPP
|
||||
@@ -43,7 +43,7 @@ template <class T, typename = typename std::enable_if<std::is_integral<T>::value
|
||||
void boost_redis_to_bulk(std::string& payload, T n)
|
||||
{
|
||||
auto const s = std::to_string(n);
|
||||
boost_redis_to_bulk(payload, std::string_view{s});
|
||||
boost::redis::resp3::boost_redis_to_bulk(payload, std::string_view{s});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
||||
Reference in New Issue
Block a user