diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 456af7ebbe..a6153b8071 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -24,6 +24,24 @@ NAMESPACE_BEGIN(detail) #define PYBIND11_AS_STRING PyString_AsString #endif +#if PY_MAJOR_VERSION >= 3 +#define PYBIND11_AS_STRING_AND_SIZE PyBytes_AsStringAndSize +#else +#define PYBIND11_AS_STRING_AND_SIZE PyString_AsStringAndSize +#endif + +#if PY_MAJOR_VERSION >= 3 +#define PYBIND11_FROM_STRING PyBytes_FromString +#else +#define PYBIND11_FROM_STRING PyString_FromString +#endif + +#if PY_MAJOR_VERSION >= 3 +#define PYBIND11_FROM_STRING_AND_SIZE PyBytes_FromStringAndSize +#else +#define PYBIND11_FROM_STRING_AND_SIZE PyString_FromStringAndSize +#endif + /** Linked list descriptor type for function signatures (produces smaller binaries compared to a previous solution using std::string and operator +=) */ class descr { @@ -336,35 +354,55 @@ template <> class type_caster { template <> class type_caster { public: bool load(PyObject *src, bool) { -#if PY_MAJOR_VERSION < 3 - if (PyString_Check(src)) { value = PyString_AsString(src); return true; } -#endif - object temp(PyUnicode_AsUTF8String(src), false); - const char *ptr = nullptr; - if (temp) - ptr = PYBIND11_AS_STRING(temp.ptr()); - if (!ptr) { PyErr_Clear(); return false; } - value = ptr; + object temp; + PyObject *load_src = src; + if (PyUnicode_Check(src)) { + temp = object(PyUnicode_AsUTF8String(src), false); + if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError + load_src = temp.ptr(); + } + char *buffer; + Py_ssize_t length; + int err = PYBIND11_AS_STRING_AND_SIZE(load_src, &buffer, &length); + if (err == -1) { PyErr_Clear(); return false; } // TypeError + value = std::string(buffer, length); return true; } static PyObject *cast(const std::string &src, return_value_policy /* policy */, PyObject * /* parent */) { return PyUnicode_FromString(src.c_str()); } +#if PY_MAJOR_VERSION >= 3 PYBIND11_TYPE_CASTER(std::string, "str"); +#else + PYBIND11_TYPE_CASTER(std::string, "unicode"); +#endif +}; + +template class type_caster> : public type_caster { +public: + static PyObject *cast(const bytes &src, return_value_policy /* policy */, PyObject * /* parent */) { + return PYBIND11_FROM_STRING_AND_SIZE(src.data(), src.size()); + } +#if PY_MAJOR_VERSION >= 3 + PYBIND11_TYPE_CASTER(bytes, "bytes"); +#else + PYBIND11_TYPE_CASTER(bytes, "str"); +#endif }; template <> class type_caster { public: bool load(PyObject *src, bool) { -#if PY_MAJOR_VERSION < 3 - if (PyString_Check(src)) { value = PyString_AsString(src); return true; } -#endif - object temp(PyUnicode_AsUTF8String(src), false); - const char *ptr = nullptr; - if (temp) - ptr = PYBIND11_AS_STRING(temp.ptr()); - if (!ptr) { PyErr_Clear(); return false; } - value = ptr; + object temp; + PyObject *load_src = src; + if (PyUnicode_Check(src)) { + temp = object(PyUnicode_AsUTF8String(src), false); + if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError + load_src = temp.ptr(); + } + const char *ptr = PYBIND11_AS_STRING(load_src); + if (!ptr) { PyErr_Clear(); return false; } // TypeError + value = std::string(ptr); return true; } diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 01776d7eb3..0b1ad5e1c0 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -259,6 +259,16 @@ inline iterator handle::end() { return iterator(nullptr); } PYBIND11_OBJECT(Name, Parent, CheckFun) \ Name() : Parent() { } +template +class bytes : public T { +public: + using T::T; + + bytes(const T& src) : T(src) { } + bytes(T&& src) : T(std::move(src)) { } + bytes() : T() { } +}; + class str : public object { public: PYBIND11_OBJECT_DEFAULT(str, object, PyUnicode_Check)