diff --git a/README.md b/README.md index 802d4ebf..85172cc1 100644 --- a/README.md +++ b/README.md @@ -92,6 +92,7 @@ Significant features and/or improvements to the code were contributed by Jonas Adler, Sylvain Corlay, Axel Huebl, +@hulucc, Johan Mabille, Tomasz Miąsko, and Ben Pritchard. diff --git a/docs/basics.rst b/docs/basics.rst index 53a325e8..cb8962c5 100644 --- a/docs/basics.rst +++ b/docs/basics.rst @@ -241,10 +241,14 @@ as arguments and return values, refer to the section on binding :ref:`classes`. +----------------------------+--------------------------+-----------------------+ | char | Character literal | pybind11/pybind11.h | +----------------------------+--------------------------+-----------------------+ +| wchar_t | Wide character literal | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ | const char * | UTF-8 string literal | pybind11/pybind11.h | +----------------------------+--------------------------+-----------------------+ | std::string | STL dynamic UTF-8 string | pybind11/pybind11.h | +----------------------------+--------------------------+-----------------------+ +| std::wstring | STL dynamic wide string | pybind11/pybind11.h | ++----------------------------+--------------------------+-----------------------+ | std::pair | Pair of two custom types | pybind11/pybind11.h | +----------------------------+--------------------------+-----------------------+ | std::tuple<....> | Arbitrary tuple of types | pybind11/pybind11.h | diff --git a/docs/changelog.rst b/docs/changelog.rst index 3aae65b3..00fd2ead 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -5,8 +5,7 @@ Changelog 1.4 (not yet released) -------------------------- -TBD - +* Transparent type conversion for ``std::wstring`` and ``wchar_t`` 1.3 (March 8, 2016) -------------------------- diff --git a/example/example2.cpp b/example/example2.cpp index 3282a85d..b137f99d 100644 --- a/example/example2.cpp +++ b/example/example2.cpp @@ -60,9 +60,9 @@ public: } /* C++ STL data types are automatically casted */ - std::vector get_list_2() { - std::vector list; - list.push_back("value"); + std::vector get_list_2() { + std::vector list; + list.push_back(L"value"); return list; } @@ -103,10 +103,10 @@ public: } /* STL data types (such as vectors) are automatically casted from Python */ - void print_list_2(std::vector &list) { + void print_list_2(std::vector &list) { int index = 0; for (auto item : list) - std::cout << "list item " << index++ << ": " << item << std::endl; + std::wcout << L"list item " << index++ << L": " << item << std::endl; } /* pybind automatically translates between C++11 and Python tuples */ diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 38918ee8..f22b6701 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -349,22 +349,45 @@ public: PYBIND11_TYPE_CASTER(std::string, _(PYBIND11_STRING_NAME)); }; -template <> class type_caster { +template <> class type_caster { public: - bool load(handle src, bool) { - object temp; - handle load_src = src; - if (PyUnicode_Check(load_src.ptr())) { - temp = object(PyUnicode_AsUTF8String(load_src.ptr()), false); - if (!temp) { PyErr_Clear(); return false; } // UnicodeEncodeError - load_src = temp; + bool load(handle src, bool) { + object temp; + handle load_src = src; + if (!PyUnicode_Check(load_src.ptr())) { + temp = object(PyUnicode_FromObject(load_src.ptr()), false); + if (!temp) { PyErr_Clear(); return false; } + load_src = temp; + } + wchar_t *buffer = nullptr; + ssize_t length = -1; +#if PY_MAJOR_VERSION >= 3 + buffer = PyUnicode_AsWideCharString(load_src.ptr(), &length); +#else + temp = object( + sizeof(wchar_t) == sizeof(short) + ? PyUnicode_AsUTF16String(load_src.ptr()) + : PyUnicode_AsUTF32String(load_src.ptr()), false); + if (temp) { + int err = PYBIND11_BYTES_AS_STRING_AND_SIZE(temp.ptr(), (char **) &buffer, &length); + if (err == -1) { buffer = nullptr; } // TypeError + length = length / sizeof(wchar_t) - 1; ++buffer; // Skip BOM } - const char *ptr = PYBIND11_BYTES_AS_STRING(load_src.ptr()); - if (!ptr) { PyErr_Clear(); return false; } // TypeError - value = std::string(ptr); - return true; - } +#endif + if (!buffer) { PyErr_Clear(); return false; } + value = std::wstring(buffer, length); + return true; + } + static handle cast(const std::wstring &src, return_value_policy /* policy */, handle /* parent */) { + return PyUnicode_FromWideChar(src.c_str(), src.length()); + } + + PYBIND11_TYPE_CASTER(std::wstring, _(PYBIND11_STRING_NAME)); +}; + +template <> class type_caster : public type_caster { +public: static handle cast(const char *src, return_value_policy /* policy */, handle /* parent */) { return PyUnicode_FromString(src); } @@ -382,6 +405,25 @@ protected: std::string value; }; +template <> class type_caster : public type_caster { +public: + static handle cast(const wchar_t *src, return_value_policy /* policy */, handle /* parent */) { + return PyUnicode_FromWideChar(src, wcslen(src)); + } + + static handle cast(wchar_t src, return_value_policy /* policy */, handle /* parent */) { + wchar_t wstr[2] = { src, L'\0' }; + return PyUnicode_FromWideChar(wstr, 1); + } + + operator wchar_t*() { return (wchar_t *)value.c_str(); } + operator wchar_t() { if (value.length() > 0) return value[0]; else return L'\0'; } + + static PYBIND11_DESCR name() { return type_descr(_(PYBIND11_STRING_NAME)); } +protected: + std::wstring value; +}; + template class type_caster> { typedef std::pair type; public: