00001 #ifndef toast_python_optional_h
00002 #define toast_python_optional_h
00003
00004 #include <boost/python.hpp>
00005 #include <boost/optional.hpp>
00006 #include <toast/assert.hpp>
00007
00016 namespace toast {
00017 namespace python {
00018
00024 template <typename T, typename TfromPy>
00025 struct object_from_python
00026 {
00027 object_from_python() {
00028 boost::python::converter::registry::push_back
00029 (&TfromPy::convertible, &TfromPy::construct,
00030 boost::python::type_id<T>());
00031 }
00032 };
00033
00034 template <typename T, typename TtoPy, typename TfromPy>
00035 struct register_python_conversion
00036 {
00037 register_python_conversion() {
00038 boost::python::to_python_converter<T, TtoPy>();
00039 object_from_python<T, TfromPy>();
00040 }
00041 };
00042
00043
00052 template <typename T>
00053 struct register_optional : public boost::noncopyable
00054 {
00055 struct optional_to_python
00056 {
00057 static PyObject * convert(const boost::optional<T>& value)
00058 {
00059 return (value ? boost::python::to_python_value<T>()(*value) :
00060 boost::python::detail::none());
00061 }
00062 };
00063
00064 struct optional_from_python
00065 {
00066 static void * convertible(PyObject * source)
00067 {
00068 using namespace boost::python::converter;
00069
00070 if (source == Py_None)
00071 return source;
00072
00073 const registration& converters(registered<T>::converters);
00074
00075 if (implicit_rvalue_convertible_from_python(source,
00076 converters)) {
00077 rvalue_from_python_stage1_data data =
00078 rvalue_from_python_stage1(source, converters);
00079 return rvalue_from_python_stage2(source, data, converters);
00080 }
00081 return NULL;
00082 }
00083
00084 static void construct(PyObject * source,
00085 boost::python::converter::rvalue_from_python_stage1_data * data)
00086 {
00087 using namespace boost::python::converter;
00088
00089 void * const storage = ((rvalue_from_python_storage<boost::optional<T> > *)
00090 data)->storage.bytes;
00091
00092 if (data->convertible == source)
00093 new (storage) boost::optional<T>();
00094 else
00095 new (storage) boost::optional<T>(*static_cast<T *>(data->convertible));
00096
00097 data->convertible = storage;
00098 }
00099 };
00100
00101 explicit register_optional() {
00102 register_python_conversion<boost::optional<T>,
00103 optional_to_python, optional_from_python>();
00104 }
00105 };
00106
00107 template <>
00108 struct register_optional<double> : public boost::noncopyable
00109 {
00110 struct optional_to_python
00111 {
00112 static PyObject * convert(const boost::optional<double>& value)
00113 {
00114 return (value ? PyFloat_FromDouble(*value) :
00115 boost::python::detail::none());
00116 }
00117 };
00118
00119 struct optional_from_python
00120 {
00121 static void * convertible(PyObject * source)
00122 {
00123 using namespace boost::python::converter;
00124
00125 if (source == Py_None || PyFloat_Check(source))
00126 return source;
00127
00128 return 0;
00129 }
00130
00131 static void construct(PyObject * source,
00132 boost::python::converter::rvalue_from_python_stage1_data * data)
00133 {
00134 TOAST_ASSERT(data->convertible == source);
00135
00136 using namespace boost::python::converter;
00137
00138 void * const storage = ((rvalue_from_python_storage<boost::optional<double> > *)
00139 data)->storage.bytes;
00140
00141 if (source == Py_None)
00142 new (storage) boost::optional<double>();
00143 else
00144 new (storage) boost::optional<double>(PyFloat_AsDouble(source));
00145
00146 data->convertible = storage;
00147 }
00148 };
00149
00150 explicit register_optional() {
00151 register_python_conversion<boost::optional<double>,
00152 optional_to_python, optional_from_python>();
00153 }
00154 };
00155
00159 }
00160 }
00161
00162
00163 #endif