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