3 #include <ozo/result.h>
5 #include <ozo/type_traits.h>
6 #include <ozo/io/size_of.h>
7 #include <ozo/core/concept.h>
8 #include <ozo/detail/endian.h>
9 #include <ozo/detail/float.h>
10 #include <ozo/io/istream.h>
11 #include <ozo/io/type_traits.h>
12 #include <boost/core/demangle.hpp>
13 #include <boost/hana/for_each.hpp>
14 #include <boost/hana/members.hpp>
15 #include <boost/hana/size.hpp>
19 constexpr std::tuple<boost::mpl::int_<I>...>
20 make_mpl_index_sequence(std::integer_sequence<int, I...>) {
25 constexpr
auto make_index_sequence(boost::mpl::int_<N>) {
26 return make_mpl_index_sequence(
27 std::make_integer_sequence<int, N>{}
31 template <
typename Adt,
typename Index>
32 constexpr decltype(
auto) member_name(const Adt&, const Index&) {
33 return fusion::extension::struct_member_name<Adt, Index::value>::call();
36 template <
typename Adt,
typename Index>
37 constexpr decltype(
auto) member_value(Adt&& v, const Index&) {
38 return fusion::at<Index>(std::forward<Adt>(v));
75 template <
typename Out,
typename = std::
void_t<>>
88 template <
typename O
idMap>
90 auto& real_out = [&] {
91 if constexpr (StrongTypedef<Out>) {
92 return std::ref(
static_cast<typename Out::base_type&
>(out));
94 return std::ref(
static_cast<Out&
>(out));
99 Writable<decltype(real_out)> || !Readable<decltype(real_out)>,
100 "Out type object can't be received. Probably it is read only type"
101 " or it is an adapted struct with read only field."
105 Writable<decltype(real_out)>,
106 "Out type object can't be received. Probably it is not an arithmetic"
107 " or doesn't have non const data and size methods "
108 " or it is a struct with field which can't be received."
111 if constexpr (DynamicSize<Out>) {
112 static_assert(Resizable<decltype(real_out)>,
113 "Out type object has dynamic size but doesn't have resize method."
115 real_out.resize(size);
116 }
else if (size !=
size_of(real_out)) {
118 "data size " + std::to_string(size)
119 +
" does not match type size " + std::to_string(
size_of(real_out)));
121 return read(in, real_out);
127 template <
typename T,
typename = std::
void_t<>>
128 struct recv_impl_dispatcher {
using type = recv_impl<std::decay_t<T>>; };
130 template <
typename T>
131 using get_recv_impl =
typename recv_impl_dispatcher<unwrap_type<T>>::type;
133 template <
typename O
idMap,
typename O
id,
typename Out>
134 inline istream&
recv(istream& in, [[maybe_unused]] Oid oid,
size_type size,
const OidMap& oids, Out& out) {
135 static_assert(std::is_same_v<Oid, oid_t>||std::is_same_v<Oid, null_oid_t>,
136 "oid must be oid_t or null_oid_t type");
138 if constexpr (Nullable<Out>) {
139 if (size == null_state_size) {
145 if constexpr (!std::is_same_v<Oid, null_oid_t>) {
148 + std::to_string(oid) +
" for type "
149 + boost::core::demangle(
typeid(unwrap_type<Out>).name()));
153 if constexpr (Nullable<Out>) {
155 }
else if (size == null_state_size) {
156 throw std::invalid_argument(
"unexpected null for type "
157 + boost::core::demangle(
typeid(out).name()));
160 return detail::get_recv_impl<Out>::apply(in, size, oids,
ozo::unwrap(out));
163 template <
typename O
idMap,
typename O
id,
typename Out>
167 return recv(in, oid, size, oids, out);
199 template <
typename O
idMap,
typename Out>
220 template <
typename O
idMap,
typename Out>
241 template <
typename O
idMap,
typename Out>
248 template <
typename T,
typename O
idMap,
typename Out>
249 void recv(
const value<T>& in,
const OidMap& oids, Out& out) {
250 istream s(in.data(), in.size());
251 recv(s, in.oid(), (in.is_null() ? null_state_size : in.size()), oids, out);
254 template <
typename T,
typename O
idMap,
typename Out>
255 Require<!FusionSequence<Out> && !FusionAdaptedStruct<Out> && !HanaStruct<Out>>
256 recv_row(
const row<T>& in,
const OidMap& oid_map, Out& out) {
257 if (std::size(in) != 1) {
258 throw std::range_error(
"row size " + std::to_string(std::size(in))
259 +
" does not equal 1 for single column result");
262 recv(*(in.begin()), oid_map, out);
265 template <
typename T,
typename O
idMap,
typename Out>
266 Require<FusionSequence<Out> && !FusionAdaptedStruct<Out> && !HanaStruct<Out>>
267 recv_row(
const row<T>& in,
const OidMap& oid_map, Out& out) {
269 if (
static_cast<std::size_t
>(fusion::size(out)) != std::size(in)) {
270 throw std::range_error(
"row size " + std::to_string(std::size(in))
271 +
" does not match sequence " + boost::core::demangle(
typeid(out).name())
272 +
" size " + std::to_string(fusion::size(out)));
276 fusion::for_each(out, [&](
auto& item) {
277 recv(*i, oid_map, item);
282 template <
typename T,
typename O
idMap,
typename Out>
283 Require<FusionAdaptedStruct<Out> && !HanaStruct<Out>>
284 recv_row(
const row<T>& in,
const OidMap& oid_map, Out& out) {
286 if (
static_cast<std::size_t
>(fusion::size(out)) != std::size(in)) {
287 throw std::range_error(
"row size " + std::to_string(std::size(in))
288 +
" does not match structure " + boost::core::demangle(
typeid(out).name())
289 +
" size " + std::to_string(fusion::size(out)));
292 fusion::for_each(make_index_sequence(fusion::size(out)), [&](
auto idx) {
293 auto i = in.find(member_name(out, idx));
295 throw std::range_error(std::string(
"row does not contain \"")
296 + member_name(out, idx) +
"\" column for "
297 + boost::core::demangle(typeid(out).name()));
299 recv(*i, oid_map, member_value(out, idx));
304 template <
typename T,
typename O
idMap,
typename Out>
305 Require<HanaStruct<Out>>
306 recv_row(
const row<T>& in,
const OidMap& oid_map, Out& out) {
308 const auto keys = hana::keys(out);
309 const auto size =
size_type(hana::value(hana::size(keys)));
310 if (size != std::size(in)) {
311 throw std::range_error(
"row size " + std::to_string(std::size(in))
312 +
" does not match structure " + boost::core::demangle(
typeid(out).name())
313 +
" size " + std::to_string(size));
316 hana::for_each(keys, [&](
auto key) {
317 auto i = in.find(hana::to<const char*>(key));
319 throw std::range_error(std::string(
"row does not contain \"")
320 + hana::to<const char*>(key) +
"\" column for "
321 + boost::core::demangle(typeid(out).name()));
323 recv(*i, oid_map, hana::at_key(out, key));
328 template <
typename T,
typename O
idMap,
typename Out>
329 Require<ForwardIterator<Out>, Out>
330 recv_result(
const basic_result<T>& in,
const OidMap& oid_map, Out out) {
331 for (
auto row : in) {
332 recv_row(row, oid_map, *out++);
337 template <
typename T,
typename O
idMap,
typename Out>
338 Require<InsertIterator<Out>, Out>
339 recv_result(
const basic_result<T>& in,
const OidMap& oid_map, Out out) {
340 for (
auto row : in) {
341 typename Out::container_type::value_type v{};
342 recv_row(row, oid_map, v);
343 *out++ = std::move(v);
348 template <
typename T,
typename O
idMap>
349 basic_result<T>& recv_result(basic_result<T>& in,
const OidMap&, basic_result<T>& out) {
354 template <
typename T,
typename O
idMap,
typename Out>
355 basic_result<T>& recv_result(basic_result<T>& in,
const OidMap& oid_map, std::reference_wrapper<Out> out) {
356 return recv_result(in, oid_map, out.get());