#include "boost/python.hpp"
#include "boost/python/object.hpp" //len function
#include "boost/python/ssize_t.hpp" //ssize_t type definition
#include "boost/python/detail/none.hpp"
#include "tuples.hpp"
/**
* Custom r-value converter example.
*
* Use-case description. I and few other developers work on Python bindings for
* Ogre (http://ogre3d.org). The engine defines ColourValue class. This class
* describes colour using 4 components: red, green, blue and transparency. The
* class is used through the whole engine. One of the first features users ask
* is to add an ability to pass a tuple, instead of the "ColourValue" instance.
* This feature would allow them to write less code:
*
* x.do_smth( (1,2,3,4) )
*
* instead of
*
* x.do_smth( ogre.ColourValue( 1,2,3,4 ) )
*
* That's not all. They also wanted to be able to use ColourValue functionality.
*
* Solution.
*
* Fortunately, Boost.Python library provides enough functionality to implement
* users requirements - r-value converters.
*
* R-Value converters allow one to register custom conallows one torom Python type to
* C++ type. The conversion will be handled by Boost.Python library automatically
* "on-the-fly".
*
* The example introduces "colour_t" class and few testers.
*
**/
struct colour_t{
explicit colour_t( float red_=0.0, float green_=0.0, float blue_=0.0 )
: red( red_ ), green( green_ ), blue( blue_ )
{}
bool operator==( const colour_t& other ) const{
return red == other.red && green == other.green && blue == other.blue;
}
float red, green, blue;
};
struct desktop_t{
bool is_same_colour( const colour_t& colour ) const{
return colour == background;
}
colour_t background;
};
namespace bpl = boost::python;
struct pytuple2colour{
typedef boost::tuples::tuple< float, float, float> colour_tuple_type;
typedef bpl::from_py_sequence< colour_tuple_type > converter_type;
static void* convertible(PyObject* obj){
return converter_type::convertible( obj );
}
static void
construct( PyObject* obj, bpl::converter::rvalue_from_python_stage1_data* data){
typedef bpl::converter::rvalue_from_python_storage<colour_t> colour_storage_t;
colour_storage_t* the_storage = reinterpret_cast<colour_storage_t*>( data );
void* memory_chunk = the_storage->storage.bytes;
float red(0.0), green(0.0), blue(0.0);
boost::tuples::tie(red, green, blue) = converter_type::to_c_tuple( obj );
colour_t* colour = new (memory_chunk) colour_t(red, green, blue);
data->convertible = memory_chunk;
}
};
void register_pytuple2colour(){
bpl::converter::registry::push_back( &pytuple2colour::convertible
, &pytuple2colour::construct
, bpl::type_id<colour_t>() );
}
bool test_val_010( colour_t colour ){
return colour == colour_t( 0, 1, 0);
}
bool test_cref_000( const colour_t& colour ){
return colour == colour_t( 0, 0, 0);
}
bool test_ref_111( colour_t& colour ){
return colour == colour_t( 1, 1, 1);
}
bool test_ptr_101( colour_t* colour ){
return colour && *colour == colour_t( 1, 0, 1);
}
bool test_cptr_110( const colour_t* colour ){
return colour && *colour == colour_t( 1, 1, 0);
}
BOOST_PYTHON_MODULE( custom_rvalue ){
bpl::class_< colour_t >( "colour_t" )
.def( bpl::init< bpl::optional< float, float, float > >(
( bpl::arg("red_")=0.0, bpl::arg("green_")=0.0, bpl::arg("blue_")=0.0 ) ) )
.def_readwrite( "red", &colour_t::red )
.def_readwrite( "green", &colour_t::green )
.def_readwrite( "blue", &colour_t::blue );
register_pytuple2colour();
bpl::class_< desktop_t >( "desktop_t" )
//naive aproach that will not work - plain Python assignment
//.def_readwrite( "background", &desktop_t::background )
//You should use properties to force the conversion
.add_property( "background"
, bpl::make_getter( &desktop_t::background )
, bpl::make_setter( &desktop_t::background ) )
.def( "is_same_colour", &desktop_t::is_same_colour );
bpl::def("test_val_010", &::test_val_010);
bpl::def("test_cref_000", &::test_cref_000);
bpl::def("test_ref_111", &::test_ref_111);
bpl::def("test_ptr_101", &::test_ptr_101);
bpl::def("test_cptr_110", &::test_cptr_110);
}