Working type casters for wide strings and wide characters
diff --git a/README.md b/README.md
index 802d4eb..85172cc 100644
--- a/README.md
+++ b/README.md
@@ -92,6 +92,7 @@
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 53a325e..cb8962c 100644
--- a/docs/basics.rst
+++ b/docs/basics.rst
@@ -241,10 +241,14 @@
+----------------------------+--------------------------+-----------------------+
| 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<T1, T2> | 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 3aae65b..00fd2ea 100644
--- a/docs/changelog.rst
+++ b/docs/changelog.rst
@@ -5,8 +5,7 @@
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 3282a85..b137f99 100644
--- a/example/example2.cpp
+++ b/example/example2.cpp
@@ -60,9 +60,9 @@
}
/* C++ STL data types are automatically casted */
- std::vector<std::string> get_list_2() {
- std::vector<std::string> list;
- list.push_back("value");
+ std::vector<std::wstring> get_list_2() {
+ std::vector<std::wstring> list;
+ list.push_back(L"value");
return list;
}
@@ -103,10 +103,10 @@
}
/* STL data types (such as vectors) are automatically casted from Python */
- void print_list_2(std::vector<std::string> &list) {
+ void print_list_2(std::vector<std::wstring> &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 38918ee..f22b670 100644
--- a/include/pybind11/cast.h
+++ b/include/pybind11/cast.h
@@ -349,22 +349,45 @@
PYBIND11_TYPE_CASTER(std::string, _(PYBIND11_STRING_NAME));
};
-template <> class type_caster<char> {
+template <> class type_caster<std::wstring> {
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<char> : public type_caster<std::string> {
+public:
static handle cast(const char *src, return_value_policy /* policy */, handle /* parent */) {
return PyUnicode_FromString(src);
}
@@ -382,6 +405,25 @@
std::string value;
};
+template <> class type_caster<wchar_t> : public type_caster<std::wstring> {
+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 <typename T1, typename T2> class type_caster<std::pair<T1, T2>> {
typedef std::pair<T1, T2> type;
public: