1 //
2 // MessagePack for C++ static resolution routine
3 //
4 // Copyright (C) 2015-2016 KONDO Takatoshi
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // (See accompanying file LICENSE_1_0.txt or copy at
8 // http://www.boost.org/LICENSE_1_0.txt)
9 //
10 #ifndef MSGPACK_V1_TYPE_BOOST_FUSION_HPP
11 #define MSGPACK_V1_TYPE_BOOST_FUSION_HPP
12
13 #include "msgpack/versioning.hpp"
14 #include "msgpack/adaptor/adaptor_base.hpp"
15 #include "msgpack/adaptor/check_container_size.hpp"
16 #include "msgpack/meta.hpp"
17
18 #include "msgpack/adaptor/pair.hpp"
19
20 #if !defined (MSGPACK_USE_CPP03)
21 #include "msgpack/adaptor/cpp11/tuple.hpp"
22 #endif // #if !defined (MSGPACK_USE_CPP03)
23
24 #include <boost/fusion/support/is_sequence.hpp>
25 #include <boost/fusion/sequence/intrinsic/size.hpp>
26 #include <boost/fusion/algorithm/iteration/for_each.hpp>
27 #include <boost/fusion/sequence/intrinsic/at.hpp>
28 #include <boost/fusion/include/mpl.hpp>
29 #include <boost/mpl/size.hpp>
30
31 namespace msgpack {
32
33 /// @cond
MSGPACK_API_VERSION_NAMESPACE(v1)34 MSGPACK_API_VERSION_NAMESPACE(v1) {
35 /// @endcond
36
37 namespace adaptor {
38
39 namespace detail {
40
41 template <typename T>
42 struct is_std_pair {
43 static bool const value = false;
44 };
45
46 template <typename T, typename U>
47 struct is_std_pair<std::pair<T, U> > {
48 static bool const value = true;
49 };
50
51 #if !defined(MSGPACK_USE_CPP03)
52
53 template <typename T>
54 struct is_std_tuple {
55 static bool const value = false;
56 };
57
58 template <typename... Args>
59 struct is_std_tuple<std::tuple<Args...>> {
60 static bool const value = true;
61 };
62
63 #endif // !defined(MSGPACK_USE_CPP03)
64
65 template <typename T>
66 struct is_seq_no_pair_no_tuple {
67 static bool const value =
68 boost::fusion::traits::is_sequence<T>::value
69 &&
70 !is_std_pair<T>::value
71 #if !defined (MSGPACK_USE_CPP03)
72 &&
73 !is_std_tuple<T>::value
74 #endif // !defined (MSGPACK_USE_CPP03)
75 ;
76 };
77
78 } // namespace detail
79
80 #if !defined (MSGPACK_USE_CPP03)
81
82 template <typename T>
83 struct as<
84 T,
85 typename msgpack::enable_if<
86 detail::is_seq_no_pair_no_tuple<T>::value &&
87 boost::mpl::fold<
88 T,
89 boost::mpl::bool_<true>,
90 boost::mpl::if_ <
91 boost::mpl::or_<
92 boost::mpl::_1,
93 msgpack::has_as<boost::mpl::_2>
94 >,
95 boost::mpl::bool_<true>,
96 boost::mpl::bool_<false>
97 >
98 >::type::value
99 >::type
100 > {
101 T operator()(msgpack::object const& o) const {
102 if (o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); }
103 if (o.via.array.size != checked_get_container_size(boost::mpl::size<T>::value)) {
104 throw msgpack::type_error();
105 }
106 using tuple_t = decltype(to_tuple(std::declval<T>(), gen_seq<boost::mpl::size<T>::value>()));
107 return to_t(
108 o.as<tuple_t>(),
109 msgpack::gen_seq<boost::mpl::size<T>::value>());
110 }
111 template<std::size_t... Is, typename U>
112 static std::tuple<
113 typename std::remove_reference<
114 typename boost::fusion::result_of::at_c<T, Is>::type
115 >::type...>
116 to_tuple(U const& u, seq<Is...>) {
117 return std::make_tuple(boost::fusion::at_c<Is>(u)...);
118 }
119 template<std::size_t... Is, typename U>
120 static T to_t(U const& u, seq<Is...>) {
121 return T(std::get<Is>(u)...);
122 }
123 };
124
125 #endif // !defined (MSGPACK_USE_CPP03)
126
127 template <typename T>
128 struct convert<T, typename msgpack::enable_if<detail::is_seq_no_pair_no_tuple<T>::value>::type > {
129 msgpack::object const& operator()(msgpack::object const& o, T& v) const {
130 if (o.type != msgpack::type::ARRAY) { throw msgpack::type_error(); }
131 if (o.via.array.size != checked_get_container_size(boost::fusion::size(v))) {
132 throw msgpack::type_error();
133 }
134 uint32_t index = 0;
135 boost::fusion::for_each(v, convert_imp(o, index));
136 return o;
137 }
138 private:
139 struct convert_imp {
140 convert_imp(msgpack::object const& obj, uint32_t& index):obj_(obj), index_(index) {}
141 template <typename U>
142 void operator()(U& v) const {
143 msgpack::adaptor::convert<U>()(obj_.via.array.ptr[index_++], v);
144 }
145 private:
146 msgpack::object const& obj_;
147 uint32_t& index_;
148 };
149 };
150
151 template <typename T>
152 struct pack<T, typename msgpack::enable_if<detail::is_seq_no_pair_no_tuple<T>::value>::type > {
153 template <typename Stream>
154 msgpack::packer<Stream>& operator()(msgpack::packer<Stream>& o, const T& v) const {
155 uint32_t size = checked_get_container_size(boost::fusion::size(v));
156 o.pack_array(size);
157 boost::fusion::for_each(v, pack_imp<Stream>(o));
158 return o;
159 }
160 private:
161 template <typename Stream>
162 struct pack_imp {
163 pack_imp(msgpack::packer<Stream>& stream):stream_(stream) {}
164 template <typename U>
165 void operator()(U const& v) const {
166 stream_.pack(v);
167 }
168 private:
169 msgpack::packer<Stream>& stream_;
170 };
171 };
172
173 template <typename T>
174 struct object_with_zone<T, typename msgpack::enable_if<detail::is_seq_no_pair_no_tuple<T>::value>::type > {
175 void operator()(msgpack::object::with_zone& o, const T& v) const {
176 uint32_t size = checked_get_container_size(boost::fusion::size(v));
177 o.type = msgpack::type::ARRAY;
178 o.via.array.ptr = static_cast<msgpack::object*>(o.zone.allocate_align(sizeof(msgpack::object)*size, MSGPACK_ZONE_ALIGNOF(msgpack::object)));
179 o.via.array.size = size;
180 uint32_t count = 0;
181 boost::fusion::for_each(v, with_zone_imp(o, count));
182 }
183 private:
184 struct with_zone_imp {
185 with_zone_imp(msgpack::object::with_zone const& obj, uint32_t& count):obj_(obj), count_(count) {}
186 template <typename U>
187 void operator()(U const& v) const {
188 obj_.via.array.ptr[count_++] = msgpack::object(v, obj_.zone);
189 }
190 msgpack::object::with_zone const& obj_;
191 uint32_t& count_;
192 };
193 };
194
195 } // namespace adaptor
196
197 /// @cond
198 } // MSGPACK_API_VERSION_NAMESPACE(v1)
199 /// @endcond
200
201 } // namespace msgpack
202
203 #endif // MSGPACK_V1_TYPE_BOOST_FUSION_HPP
204