Python package Pybind11 type

Custom type caster

Ref: https://pybind11.readthedocs.io/en/stable/advanced/cast/custom.html

namespace pybind11
{
namespace detail
{
    template<>
    struct type_caster<lot::pin_mode_t>
    {
    public:
        /**
         * This macro establishes the name 'lot::pin_mode_t' in
         * function signatures and declares a local variable
         * 'value' of type lot::pin_mode_t
         */
        PYBIND11_TYPE_CASTER( lot::pin_mode_t, _( "lot::pin_mode_t" ) );

        /**
         * Conversion part 1 (Python->C++): convert a PyObject into
         * a lot::pin_mode_t instance or return false upon failure.
         * The second argument indicates whether implicit conversions
         * should be applied.
         */
        bool load( handle src, bool )
        {
            /* Extract PyObject from handle */
            PyObject *source = src.ptr();
            /* Try converting into a Python integer value */
            PyObject *tmp = PyNumber_Long( source );
            if( !tmp )
                return false;
            /* Now try to convert into a C++ lot::pin_mode_t */
            value = static_cast<lot::pin_mode_t>( PyLong_AsLong( tmp ) );
            Py_DECREF( tmp );
            /* Ensure return code was OK (to avoid out-of-range errors etc) */
            return !( value == -1 && !PyErr_Occurred() );
        }

        /**
         * Conversion part 2 (C++ -> Python): convert an lot::pin_mode_t
         * instance into a Python object. The second and third arguments
         * are used to indicate the return value policy and parent object
         * (for ``return_value_policy::reference_internal``) and are
         * generally ignored by implicit casters.
         */
        static handle cast( lot::pin_mode_t src,
                            return_value_policy /* policy */,
                            handle /* parent */ )
        {
            return PyLong_FromLong( static_cast<int>( src ) );
        }
    };
}    // namespace detail
}    // namespace pybind11

Class member function type casting

Use ClassWrapper or lambda function that has class as the first parameter.

Example

    /*
     * lot/Uart.h
     */
    py::class_<lot::Uart>( m, "Uart" )
        .def( py::init<const char *>() )
        .def( py::init<uint16_t>() )
        .def( "init",
              &lot::Uart::init,
              py::arg( "baud_rate" ) = 115200,
              py::arg( "uart_mode" ) = lot::U8N1 )
        .def( "baudrate", &lot::Uart::baudrate )
        .def( "mode", &lot::Uart::mode )
        .def( "available", &lot::Uart::available )
        .def( "transmit",
              []( lot::Uart &self, py::bytes data ) {
                  std::string str = data;
                  if( str.size() > 0 )
                  {
                      self.transmit( reinterpret_cast<uint8_t *>(
                                         const_cast<char *>( str.c_str() ) ),
                                     str.size() );
                  }
              } )
        .def( "receive", []( lot::Uart &self ) {
            uint16_t size = self.available();
            if( size > 0 )
            {
                uint8_t *buf = new uint8_t[size];
                self.receive( buf, size );
                py::bytes data( reinterpret_cast<const char *>( buf ), size );
                delete[] buf;
                return data;
            }
            return py::bytes( "" );
        } );

Class member lambda arguments

Register variables in order except self.

Example

        .def(
            "receive",
            []( lot::I2c &self, int slave_address, int size ) {
                if( size > 0 )
                {
                    uint8_t *buf = new uint8_t[size];
                    self.receive(
                        static_cast<uint8_t>( slave_address ), buf, size );
                    py::bytes data( reinterpret_cast<const char *>( buf ),
                                    size );
                    delete[] buf;
                    return data;
                }
                return py::bytes( "" );
            },
            // py::arg( "self" ),
            py::arg( "slave_address" ),
            py::arg( "size" ) = 1 )