1 | #include <boost/optional.hpp>
|
---|
2 | #include <boost/python.hpp>
|
---|
3 | #include <boost/python/detail/wrap_python.hpp>
|
---|
4 | #include <string>
|
---|
5 |
|
---|
6 | template <typename T, typename TfromPy>
|
---|
7 | struct object_from_python
|
---|
8 | {
|
---|
9 | object_from_python() {
|
---|
10 | boost::python::converter::registry::insert
|
---|
11 | (&TfromPy::convertible, &TfromPy::construct,
|
---|
12 | boost::python::type_id<T>());
|
---|
13 | }
|
---|
14 | };
|
---|
15 |
|
---|
16 | template <typename T, typename TtoPy, typename TfromPy>
|
---|
17 | struct register_python_conversion
|
---|
18 | {
|
---|
19 | register_python_conversion() {
|
---|
20 | boost::python::to_python_converter<T, TtoPy>();
|
---|
21 | object_from_python<T, TfromPy>();
|
---|
22 | }
|
---|
23 | };
|
---|
24 |
|
---|
25 | template <typename T>
|
---|
26 | struct register_optional_to_python : public boost::noncopyable
|
---|
27 | {
|
---|
28 | struct optional_to_python
|
---|
29 | {
|
---|
30 | static PyObject * convert(const boost::optional<T>& value)
|
---|
31 | {
|
---|
32 | return boost::python::incref
|
---|
33 | (value ? boost::python::to_python_value<T>()(*value) :
|
---|
34 | boost::python::detail::none());
|
---|
35 | }
|
---|
36 | };
|
---|
37 |
|
---|
38 | struct optional_from_python
|
---|
39 | {
|
---|
40 | static void * convertible(PyObject * source)
|
---|
41 | {
|
---|
42 | using namespace boost::python::converter;
|
---|
43 |
|
---|
44 | if (source == Py_None)
|
---|
45 | return source;
|
---|
46 |
|
---|
47 | const registration& converters(registered<T>::converters);
|
---|
48 |
|
---|
49 | if (implicit_rvalue_convertible_from_python(source, converters)) {
|
---|
50 | rvalue_from_python_stage1_data data =
|
---|
51 | rvalue_from_python_stage1(source, converters);
|
---|
52 | return rvalue_from_python_stage2(source, data, converters);
|
---|
53 | }
|
---|
54 | return NULL;
|
---|
55 | }
|
---|
56 |
|
---|
57 | static void construct(PyObject * source,
|
---|
58 | boost::python::converter::rvalue_from_python_stage1_data * data)
|
---|
59 | {
|
---|
60 | using namespace boost::python::converter;
|
---|
61 |
|
---|
62 | void * const storage =
|
---|
63 | reinterpret_cast<rvalue_from_python_storage<T> *>(data)->storage.bytes;
|
---|
64 |
|
---|
65 | if (data->convertible == source) // == None
|
---|
66 | new (storage) boost::optional<T>(); // A Boost uninitialized value
|
---|
67 | else
|
---|
68 | new (storage) boost::optional<T>(*reinterpret_cast<T *>(data->convertible));
|
---|
69 |
|
---|
70 | data->convertible = storage;
|
---|
71 | }
|
---|
72 | };
|
---|
73 |
|
---|
74 | explicit register_optional_to_python() {
|
---|
75 | register_python_conversion<boost::optional<T>,
|
---|
76 | optional_to_python, optional_from_python>();
|
---|
77 | }
|
---|
78 | };
|
---|
79 |
|
---|
80 | class amount_t
|
---|
81 | {
|
---|
82 | public:
|
---|
83 | std::string hello() { return "Hello, world!"; }
|
---|
84 | };
|
---|
85 |
|
---|
86 | class annotation_t
|
---|
87 | {
|
---|
88 | public:
|
---|
89 | boost::optional<amount_t> price;
|
---|
90 | };
|
---|
91 |
|
---|
92 | boost::optional<amount_t> py_price(annotation_t& ann) {
|
---|
93 | return ann.price;
|
---|
94 | }
|
---|
95 |
|
---|
96 | BOOST_PYTHON_MODULE(bug)
|
---|
97 | {
|
---|
98 | using namespace boost::python;
|
---|
99 |
|
---|
100 | class_< annotation_t > ("Annotation")
|
---|
101 | .add_property("price", make_getter(&annotation_t::price))
|
---|
102 | .add_property("price2", py_price)
|
---|
103 | ;
|
---|
104 |
|
---|
105 | register_optional_to_python<amount_t>();
|
---|
106 | }
|
---|