Skip to main content

Python 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)