| 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 | }
|
|---|