diff --git a/include/pms-utils/atom/atom.hpp b/include/pms-utils/atom/atom.hpp index b707c2f..676ba8c 100644 --- a/include/pms-utils/atom/atom.hpp +++ b/include/pms-utils/atom/atom.hpp @@ -136,7 +136,9 @@ struct Usedep { [[nodiscard]] explicit operator std::string() const; }; -struct Usedeps : public std::vector {}; +struct Usedeps : public std::vector { + [[nodiscard]] explicit operator std::string() const; +}; struct PackageExpr { boost::optional blocker; @@ -236,6 +238,8 @@ std::ostream &operator<<(std::ostream &out, UsedepCond usedepCond); std::ostream &operator<<(std::ostream &out, const Usedep &usedep); +std::ostream &operator<<(std::ostream &out, const Usedeps &usedeps); + std::ostream &operator<<(std::ostream &out, const PackageExpr &package); // END IO diff --git a/lib/atom/atom.cpp b/lib/atom/atom.cpp index 380b85f..d66566c 100644 --- a/lib/atom/atom.cpp +++ b/lib/atom/atom.cpp @@ -202,6 +202,22 @@ Usedep::operator std::string() const { } std::ostream &operator<<(std::ostream &out, const Usedep &usedep) { return out << std::string(usedep); } +Usedeps::operator std::string() const { + std::string ret; + if (empty()) { + return ret; + } + ret += "["; + for (const Usedep &usedep : *this) { + ret += std::string(usedep); + ret += ","; + } + ret.pop_back(); + ret += "]"; + return ret; +} +std::ostream &operator<<(std::ostream &out, const Usedeps &usedeps) { return out << std::string(usedeps); } + PackageExpr::operator std::string() const { std::string ret; if (blocker.has_value()) { @@ -221,15 +237,7 @@ PackageExpr::operator std::string() const { if (slotExpr.has_value()) { ret += std::string(slotExpr.value()); } - if (!usedeps.empty()) { - ret += "["; - for (const Usedep &usedep : usedeps) { - ret += std::string(usedep); - ret += ","; - } - ret = ret.substr(0, ret.length() - 1); - ret += "]"; - } + ret += std::string(usedeps); return ret; } diff --git a/subprojects/bindings-python/lib/common.hpp b/subprojects/bindings-python/lib/common.hpp index f3b6eaf..7f62f00 100644 --- a/subprojects/bindings-python/lib/common.hpp +++ b/subprojects/bindings-python/lib/common.hpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -40,19 +41,34 @@ template <> struct visit_helper { namespace pms_utils::bindings::python { +template +static inline py::object &add_method(py::object &cls, std::string_view name, Func &&func) { + // pybind11 needs a c_str ;/ + const std::string name_str(name); + py::cpp_function cfunc(std::forward(func), py::name(name_str.c_str()), py::is_method(cls), + py::sibling(py::getattr(cls, name_str.c_str(), py::none()))); + py::detail::add_class_method(cls, name_str.c_str(), cfunc); + return cls; +} + template requires(std::is_enum_v && boost::describe::has_describe_enumerators::value) -static inline py::object create_bindings(M module_, R rule = false, std::string enum_type = "enum.Enum") { +static inline py::object create_bindings(M module_, R rule = false, + std::string_view enum_type = "enum.Enum") { constexpr std::string_view name = bound_type_name::str; py::object ret = _internal::bind_enum(module_, name, enum_type); + + if constexpr (requires(T val) { to_string(val); }) { + add_method(ret, "__str__", [](T val) { return to_string(val); }); + } if constexpr (!std::is_same_v) { - const std::string function_name = std::string("_") + std::string(name) + "_init"; - module_.def(function_name.data(), [rule](const py::object &, std::string_view arg) { + const std::string function_name = std::string("_") + std::string(name) + "__missing_"; + module_.def(function_name.c_str(), [rule](const py::object &, std::string_view arg) { return _internal::expr_from_str(rule(), arg); }); ret.attr("_missing_") = - py::module::import("pydoc").attr("locate")("classmethod")(module_.attr(function_name.data())); + py::module::import("builtins").attr("classmethod")(module_.attr(function_name.c_str())); } return ret; } @@ -83,7 +99,7 @@ static inline auto create_bindings(M module_, R rule = false) { auto ret = pyclass(module_, std::string(name).data()); mp_for_each>( [&ret](auto member) { ret.def_readonly(member.name, member.pointer); }); - if constexpr (requires(const T &val) { std::string(val); }) { + if constexpr (std::constructible_from) { ret.def("__str__", [](const T &val) { return std::string(val); }); } if constexpr (!std::is_same_v) { diff --git a/subprojects/bindings-python/lib/enum.hpp b/subprojects/bindings-python/lib/enum.hpp index 7d0df31..3821143 100644 --- a/subprojects/bindings-python/lib/enum.hpp +++ b/subprojects/bindings-python/lib/enum.hpp @@ -18,11 +18,12 @@ namespace py = pybind11; namespace pms_utils::bindings::python::_internal { +// thanks to +// https://github.com/pybind/pybind11/issues/2332#issuecomment-741061287 + // maps enum type to python enum std::unordered_map &enums(); -std::size_t &enum_counter(); - template consteval auto bound_type_name_to_descr() { constexpr std::array myarr = bound_type_name_v; // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays) @@ -47,7 +48,7 @@ auto bind_enum(M &mod, std::string_view name, std::string_view enum_type) { py::object &spec = _internal::enums()[typeid(T)]; spec = py::module::import("pydoc").attr("locate")(enum_type)(name, pairs, py::arg("module") = mod.attr("__name__")); - mod.attr(std::string(name).data()) = spec; + mod.attr(std::string(name).c_str()) = spec; return spec; }