1 // Copyright David Abrahams 2002.
2 // Distributed under the Boost Software License, Version 1.0. (See
3 // accompanying file LICENSE_1_0.txt or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 #ifndef ARG_TO_PYTHON_DWA200265_HPP
6 # define ARG_TO_PYTHON_DWA200265_HPP
7 
8 # include <boost/python/ptr.hpp>
9 # include <boost/python/tag.hpp>
10 # include <boost/python/to_python_indirect.hpp>
11 
12 # include <boost/python/converter/registered.hpp>
13 # include <boost/python/converter/registered_pointee.hpp>
14 # include <boost/python/converter/arg_to_python_base.hpp>
15 # include <boost/python/converter/shared_ptr_to_python.hpp>
16 // Bring in specializations
17 # include <boost/python/converter/builtin_converters.hpp>
18 
19 # include <boost/python/object/function_handle.hpp>
20 
21 # include <boost/python/base_type_traits.hpp>
22 
23 # include <boost/python/detail/indirect_traits.hpp>
24 # include <boost/python/detail/convertible.hpp>
25 # include <boost/python/detail/string_literal.hpp>
26 # include <boost/python/detail/value_is_shared_ptr.hpp>
27 
28 # include <boost/type_traits/cv_traits.hpp>
29 # include <boost/type_traits/composite_traits.hpp>
30 # include <boost/type_traits/function_traits.hpp>
31 
32 
33 # include <boost/mpl/or.hpp>
34 
35 namespace boost { namespace python { namespace converter {
36 
37 template <class T> struct is_object_manager;
38 
39 namespace detail
40 {
41   template <class T>
42   struct function_arg_to_python : handle<>
43   {
44       function_arg_to_python(T const& x);
45   };
46 
47   template <class T>
48   struct reference_arg_to_python : handle<>
49   {
50       reference_arg_to_python(T& x);
51    private:
52       static PyObject* get_object(T& x);
53   };
54 
55   template <class T>
56   struct shared_ptr_arg_to_python : handle<>
57   {
58       shared_ptr_arg_to_python(T const& x);
59    private:
60       static PyObject* get_object(T& x);
61   };
62 
63   template <class T>
64   struct value_arg_to_python : arg_to_python_base
65   {
66       // Throw an exception if the conversion can't succeed
67       value_arg_to_python(T const&);
68   };
69 
70   template <class Ptr>
71   struct pointer_deep_arg_to_python : arg_to_python_base
72   {
73       // Throw an exception if the conversion can't succeed
74       pointer_deep_arg_to_python(Ptr);
75   };
76 
77   template <class Ptr>
78   struct pointer_shallow_arg_to_python : handle<>
79   {
80       // Throw an exception if the conversion can't succeed
81       pointer_shallow_arg_to_python(Ptr);
82    private:
83       static PyObject* get_object(Ptr p);
84   };
85 
86   // Convert types that manage a Python object to_python
87   template <class T>
88   struct object_manager_arg_to_python
89   {
object_manager_arg_to_pythonboost::python::converter::detail::object_manager_arg_to_python90       object_manager_arg_to_python(T const& x) : m_src(x) {}
91 
getboost::python::converter::detail::object_manager_arg_to_python92       PyObject* get() const
93       {
94           return python::upcast<PyObject>(get_managed_object(m_src, tag));
95       }
96 
97    private:
98       T const& m_src;
99   };
100 
101   template <class T>
102   struct select_arg_to_python
103   {
104       typedef typename unwrap_reference<T>::type unwrapped_referent;
105       typedef typename unwrap_pointer<T>::type unwrapped_ptr;
106 
107       typedef typename mpl::if_<
108           // Special handling for char const[N]; interpret them as char
109           // const* for the sake of conversion
110           python::detail::is_string_literal<T const>
111         , arg_to_python<char const*>
112 
113         , typename mpl::if_<
114               python::detail::value_is_shared_ptr<T>
115             , shared_ptr_arg_to_python<T>
116 
117             , typename mpl::if_<
118                 mpl::or_<
119                     is_function<T>
120                   , indirect_traits::is_pointer_to_function<T>
121                   , is_member_function_pointer<T>
122                 >
123                 , function_arg_to_python<T>
124 
125                 , typename mpl::if_<
126                       is_object_manager<T>
127                     , object_manager_arg_to_python<T>
128 
129                     , typename mpl::if_<
130                           is_pointer<T>
131                         , pointer_deep_arg_to_python<T>
132 
133                         , typename mpl::if_<
134                               is_pointer_wrapper<T>
135                             , pointer_shallow_arg_to_python<unwrapped_ptr>
136 
137                             , typename mpl::if_<
138                                   is_reference_wrapper<T>
139                                 , reference_arg_to_python<unwrapped_referent>
140                                 , value_arg_to_python<T>
141                               >::type
142                           >::type
143                       >::type
144                   >::type
145               >::type
146           >::type
147       >::type
148 
149       type;
150   };
151 }
152 
153 template <class T>
154 struct arg_to_python
155     : detail::select_arg_to_python<T>::type
156 {
157     typedef typename detail::select_arg_to_python<T>::type base;
158  public: // member functions
159     // Throw an exception if the conversion can't succeed
160     arg_to_python(T const& x);
161 };
162 
163 //
164 // implementations
165 //
166 namespace detail
167 {
168   // reject_raw_object_ptr -- cause a compile-time error if the user
169   // should pass a raw Python object pointer
170   using python::detail::yes_convertible;
171   using python::detail::no_convertible;
172   using python::detail::unspecialized;
173 
174   template <class T> struct cannot_convert_raw_PyObject;
175 
176   template <class T, class Convertibility>
177   struct reject_raw_object_helper
178   {
errorboost::python::converter::detail::reject_raw_object_helper179       static void error(Convertibility)
180       {
181           cannot_convert_raw_PyObject<T*>::to_python_use_handle_instead();
182       }
errorboost::python::converter::detail::reject_raw_object_helper183       static void error(...) {}
184   };
185 
186   template <class T>
reject_raw_object_ptr(T *)187   inline void reject_raw_object_ptr(T*)
188   {
189       reject_raw_object_helper<T,yes_convertible>::error(
190           python::detail::convertible<PyObject const volatile*>::check((T*)0));
191 
192       typedef typename remove_cv<T>::type value_type;
193 
194       reject_raw_object_helper<T,no_convertible>::error(
195           python::detail::convertible<unspecialized*>::check(
196               (base_type_traits<value_type>*)0
197               ));
198   }
199   // ---------
200 
201   template <class T>
function_arg_to_python(T const & x)202   inline function_arg_to_python<T>::function_arg_to_python(T const& x)
203       : handle<>(python::objects::make_function_handle(x))
204   {
205   }
206 
207   template <class T>
value_arg_to_python(T const & x)208   inline value_arg_to_python<T>::value_arg_to_python(T const& x)
209       : arg_to_python_base(&x, registered<T>::converters)
210   {
211   }
212 
213   template <class Ptr>
pointer_deep_arg_to_python(Ptr x)214   inline pointer_deep_arg_to_python<Ptr>::pointer_deep_arg_to_python(Ptr x)
215       : arg_to_python_base(x, registered_pointee<Ptr>::converters)
216   {
217       detail::reject_raw_object_ptr((Ptr)0);
218   }
219 
220   template <class T>
get_object(T & x)221   inline PyObject* reference_arg_to_python<T>::get_object(T& x)
222   {
223       to_python_indirect<T&,python::detail::make_reference_holder> convert;
224       return convert(x);
225   }
226 
227   template <class T>
reference_arg_to_python(T & x)228   inline reference_arg_to_python<T>::reference_arg_to_python(T& x)
229       : handle<>(reference_arg_to_python<T>::get_object(x))
230   {
231   }
232 
233   template <class T>
shared_ptr_arg_to_python(T const & x)234   inline shared_ptr_arg_to_python<T>::shared_ptr_arg_to_python(T const& x)
235       : handle<>(shared_ptr_to_python(x))
236   {
237   }
238 
239   template <class Ptr>
pointer_shallow_arg_to_python(Ptr x)240   inline pointer_shallow_arg_to_python<Ptr>::pointer_shallow_arg_to_python(Ptr x)
241       : handle<>(pointer_shallow_arg_to_python<Ptr>::get_object(x))
242   {
243       detail::reject_raw_object_ptr((Ptr)0);
244   }
245 
246   template <class Ptr>
get_object(Ptr x)247   inline PyObject* pointer_shallow_arg_to_python<Ptr>::get_object(Ptr x)
248   {
249       to_python_indirect<Ptr,python::detail::make_reference_holder> convert;
250       return convert(x);
251   }
252 }
253 
254 template <class T>
arg_to_python(T const & x)255 inline arg_to_python<T>::arg_to_python(T const& x)
256     : base(x)
257 {}
258 
259 }}} // namespace boost::python::converter
260 
261 #endif // ARG_TO_PYTHON_DWA200265_HPP
262