diff --git a/include/pybind11/stl.h b/include/pybind11/stl.h index 32f8d294ac..5d707e420d 100644 --- a/include/pybind11/stl.h +++ b/include/pybind11/stl.h @@ -41,6 +41,11 @@ # include # define PYBIND11_HAS_VARIANT 1 # endif +// std::variant +# if defined(PYBIND11_CPP17) && __has_include() +# include +# define PYBIND11_HAS_FILESYSTEM 1 +# endif #elif defined(_MSC_VER) && defined(PYBIND11_CPP17) # include # include @@ -372,6 +377,43 @@ template struct type_caster> : variant_caster> { }; #endif +#if PYBIND11_HAS_FILESYSTEM && ((PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION >= 6) || PY_MAJOR_VERSION >= 4) +template <> struct type_caster +{ +public: + PYBIND11_TYPE_CASTER(std::filesystem::path, _("path_like")); + + bool load(handle src, bool) + { + auto fs_encoded = reinterpret_steal(PyOS_FSPath(src.ptr())); + if (!fs_encoded) + { + PyErr_Clear(); + return false; + } + if (PyBytes_Check(fs_encoded.ptr())) // fs_encoded may be bytes or unicode + fs_encoded = reinterpret_steal(PyUnicode_DecodeFSDefault(PyBytes_AS_STRING(fs_encoded.ptr()))); + + auto size = Py_ssize_t{}; + auto buffer = PyUnicode_AsUTF8AndSize(fs_encoded.ptr(), &size); + if (! buffer) + { + PyErr_Clear(); + return false; + } + + value = std::filesystem::u8path(buffer, buffer + size); + return true; + } + + static handle cast(std::filesystem::path src, return_value_policy /* policy */, handle /* parent */) + { + auto data = src.u8string(); + return PyUnicode_DecodeUTF8(data.data(), data.size(), nullptr /* usually means strict */); + } +}; +#endif + NAMESPACE_END(detail) inline std::ostream &operator<<(std::ostream &os, const handle &obj) {