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
6 #include <boost/python/converter/from_python.hpp>
7 #include <boost/python/converter/registrations.hpp>
8 #include <boost/python/converter/rvalue_from_python_data.hpp>
9
10 #include <boost/python/object/find_instance.hpp>
11
12 #include <boost/python/handle.hpp>
13 #include <boost/python/detail/raw_pyobject.hpp>
14 #include <boost/python/cast.hpp>
15
16 #include <vector>
17 #include <algorithm>
18
19 namespace boost { namespace python { namespace converter {
20
21 // rvalue_from_python_stage1 -- do the first stage of a conversion
22 // from a Python object to a C++ rvalue.
23 //
24 // source - the Python object to be converted
25 // converters - the registry entry for the target type T
26 //
27 // Postcondition: where x is the result, one of:
28 //
29 // 1. x.convertible == 0, indicating failure
30 //
31 // 2. x.construct == 0, x.convertible is the address of an object of
32 // type T. Indicates a successful lvalue conversion
33 //
34 // 3. where y is of type rvalue_from_python_data<T>,
35 // x.construct(source, y) constructs an object of type T
36 // in y.storage.bytes and then sets y.convertible == y.storage.bytes,
37 // or else throws an exception and has no effect.
rvalue_from_python_stage1(PyObject * source,registration const & converters)38 BOOST_PYTHON_DECL rvalue_from_python_stage1_data rvalue_from_python_stage1(
39 PyObject* source
40 , registration const& converters)
41 {
42 rvalue_from_python_stage1_data data;
43
44 // First check to see if it's embedded in an extension class
45 // instance, as a special case.
46 data.convertible = objects::find_instance_impl(source, converters.target_type, converters.is_shared_ptr);
47 data.construct = 0;
48 if (!data.convertible)
49 {
50 for (rvalue_from_python_chain const* chain = converters.rvalue_chain;
51 chain != 0;
52 chain = chain->next)
53 {
54 void* r = chain->convertible(source);
55 if (r != 0)
56 {
57 data.convertible = r;
58 data.construct = chain->construct;
59 break;
60 }
61 }
62 }
63 return data;
64 }
65
66 // rvalue_result_from_python -- return the address of a C++ object which
67 // can be used as the result of calling a Python function.
68 //
69 // src - the Python object to be converted
70 //
71 // data - a reference to the base part of a
72 // rvalue_from_python_data<T> object, where T is the
73 // target type of the conversion.
74 //
75 // Requires: data.convertible == ®istered<T>::converters
76 //
rvalue_result_from_python(PyObject * src,rvalue_from_python_stage1_data & data)77 BOOST_PYTHON_DECL void* rvalue_result_from_python(
78 PyObject* src, rvalue_from_python_stage1_data& data)
79 {
80 // Retrieve the registration
81 // Cast in two steps for less-capable compilers
82 void const* converters_ = data.convertible;
83 registration const& converters = *static_cast<registration const*>(converters_);
84
85 // Look for an eligible converter
86 data = rvalue_from_python_stage1(src, converters);
87 return rvalue_from_python_stage2(src, data, converters);
88 }
89
rvalue_from_python_stage2(PyObject * source,rvalue_from_python_stage1_data & data,registration const & converters)90 BOOST_PYTHON_DECL void* rvalue_from_python_stage2(
91 PyObject* source, rvalue_from_python_stage1_data& data, registration const& converters)
92 {
93 if (!data.convertible)
94 {
95 handle<> msg(
96 #if PY_VERSION_HEX >= 0x03000000
97 ::PyUnicode_FromFormat
98 #else
99 ::PyString_FromFormat
100 #endif
101 (
102 "No registered converter was able to produce a C++ rvalue of type %s from this Python object of type %s"
103 , converters.target_type.name()
104 , source->ob_type->tp_name
105 ));
106
107 PyErr_SetObject(PyExc_TypeError, msg.get());
108 throw_error_already_set();
109 }
110
111 // If a construct function was registered (i.e. we found an
112 // rvalue conversion), call it now.
113 if (data.construct != 0)
114 data.construct(source, &data);
115
116 // Return the address of the resulting C++ object
117 return data.convertible;
118 }
119
get_lvalue_from_python(PyObject * source,registration const & converters)120 BOOST_PYTHON_DECL void* get_lvalue_from_python(
121 PyObject* source
122 , registration const& converters)
123 {
124 // Check to see if it's embedded in a class instance
125 void* x = objects::find_instance_impl(source, converters.target_type);
126 if (x)
127 return x;
128
129 lvalue_from_python_chain const* chain = converters.lvalue_chain;
130 for (;chain != 0; chain = chain->next)
131 {
132 void* r = chain->convert(source);
133 if (r != 0)
134 return r;
135 }
136 return 0;
137 }
138
139 namespace
140 {
141 // Prevent looping in implicit conversions. This could/should be
142 // much more efficient, but will work for now.
143 typedef std::vector<rvalue_from_python_chain const*> visited_t;
144 static visited_t visited;
145
visit(rvalue_from_python_chain const * chain)146 inline bool visit(rvalue_from_python_chain const* chain)
147 {
148 visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain);
149 if (p != visited.end() && *p == chain)
150 return false;
151 visited.insert(p, chain);
152 return true;
153 }
154
155 // RAII class for managing global visited marks.
156 struct unvisit
157 {
unvisitboost::python::converter::__anon96dfd1270111::unvisit158 unvisit(rvalue_from_python_chain const* chain)
159 : chain(chain) {}
160
~unvisitboost::python::converter::__anon96dfd1270111::unvisit161 ~unvisit()
162 {
163 visited_t::iterator const p = std::lower_bound(visited.begin(), visited.end(), chain);
164 assert(p != visited.end());
165 visited.erase(p);
166 }
167 private:
168 rvalue_from_python_chain const* chain;
169 };
170 }
171
172
implicit_rvalue_convertible_from_python(PyObject * source,registration const & converters)173 BOOST_PYTHON_DECL bool implicit_rvalue_convertible_from_python(
174 PyObject* source
175 , registration const& converters)
176 {
177 if (objects::find_instance_impl(source, converters.target_type))
178 return true;
179
180 rvalue_from_python_chain const* chain = converters.rvalue_chain;
181
182 if (!visit(chain))
183 return false;
184
185 unvisit protect(chain);
186
187 for (;chain != 0; chain = chain->next)
188 {
189 if (chain->convertible(source))
190 return true;
191 }
192
193 return false;
194 }
195
196 namespace
197 {
throw_no_lvalue_from_python(PyObject * source,registration const & converters,char const * ref_type)198 void throw_no_lvalue_from_python(PyObject* source, registration const& converters, char const* ref_type)
199 {
200 handle<> msg(
201 #if PY_VERSION_HEX >= 0x03000000
202 ::PyUnicode_FromFormat
203 #else
204 ::PyString_FromFormat
205 #endif
206 (
207 "No registered converter was able to extract a C++ %s to type %s"
208 " from this Python object of type %s"
209 , ref_type
210 , converters.target_type.name()
211 , source->ob_type->tp_name
212 ));
213
214 PyErr_SetObject(PyExc_TypeError, msg.get());
215
216 throw_error_already_set();
217 }
218
lvalue_result_from_python(PyObject * source,registration const & converters,char const * ref_type)219 void* lvalue_result_from_python(
220 PyObject* source
221 , registration const& converters
222 , char const* ref_type)
223 {
224 handle<> holder(source);
225 if (source->ob_refcnt <= 1)
226 {
227 handle<> msg(
228 #if PY_VERSION_HEX >= 0x3000000
229 ::PyUnicode_FromFormat
230 #else
231 ::PyString_FromFormat
232 #endif
233 (
234 "Attempt to return dangling %s to object of type: %s"
235 , ref_type
236 , converters.target_type.name()));
237
238 PyErr_SetObject(PyExc_ReferenceError, msg.get());
239
240 throw_error_already_set();
241 }
242
243 void* result = get_lvalue_from_python(source, converters);
244 if (!result)
245 (throw_no_lvalue_from_python)(source, converters, ref_type);
246 return result;
247 }
248
249 }
250
throw_no_pointer_from_python(PyObject * source,registration const & converters)251 BOOST_PYTHON_DECL void throw_no_pointer_from_python(PyObject* source, registration const& converters)
252 {
253 (throw_no_lvalue_from_python)(source, converters, "pointer");
254 }
255
throw_no_reference_from_python(PyObject * source,registration const & converters)256 BOOST_PYTHON_DECL void throw_no_reference_from_python(PyObject* source, registration const& converters)
257 {
258 (throw_no_lvalue_from_python)(source, converters, "reference");
259 }
260
reference_result_from_python(PyObject * source,registration const & converters)261 BOOST_PYTHON_DECL void* reference_result_from_python(
262 PyObject* source
263 , registration const& converters)
264 {
265 return (lvalue_result_from_python)(source, converters, "reference");
266 }
267
pointer_result_from_python(PyObject * source,registration const & converters)268 BOOST_PYTHON_DECL void* pointer_result_from_python(
269 PyObject* source
270 , registration const& converters)
271 {
272 if (source == Py_None)
273 {
274 Py_DECREF(source);
275 return 0;
276 }
277 return (lvalue_result_from_python)(source, converters, "pointer");
278 }
279
void_result_from_python(PyObject * o)280 BOOST_PYTHON_DECL void void_result_from_python(PyObject* o)
281 {
282 Py_DECREF(expect_non_null(o));
283 }
284
285 } // namespace boost::python::converter
286
287 BOOST_PYTHON_DECL PyObject*
pytype_check(PyTypeObject * type_,PyObject * source)288 pytype_check(PyTypeObject* type_, PyObject* source)
289 {
290 if (!PyObject_IsInstance(source, python::upcast<PyObject>(type_)))
291 {
292 ::PyErr_Format(
293 PyExc_TypeError
294 , "Expecting an object of type %s; got an object of type %s instead"
295 , type_->tp_name
296 , source->ob_type->tp_name
297 );
298 throw_error_already_set();
299 }
300 return source;
301 }
302
303 }} // namespace boost::python
304