/* Copyright 2017 - 2024 R. Thomas * Copyright 2017 - 2024 Quarkslab * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef PY_LIEF_ENUMS_WRAPPER_H #define PY_LIEF_ENUMS_WRAPPER_H #include #include #include "pyutils.hpp" #include #include #include #include "LIEF/visibility.h" namespace LIEF { template> static inline std::map get_enums_map(const nanobind::object& value) { static constexpr auto NANOBIND_ENTRIES = "@entries"; auto flags = nanobind::cast(value); auto int_value = static_cast(flags); const nanobind::dict entries = value.attr(NANOBIND_ENTRIES); std::map entries_map; for (const auto& [value, info] : entries) { auto enum_int = nanobind::cast(value); auto name = nanobind::cast(info[0]); auto enume_typed = nanobind::cast(info[2]); entries_map[enum_int] = std::move(name); } return entries_map; } template> static inline std::string flag2str(const nanobind::object& value, bool full_type) { auto flags = nanobind::cast(value); auto int_value = static_cast(flags); const std::map& entries_map = get_enums_map(value); if (auto it = entries_map.find(int_value); it != entries_map.end()) { return LIEF::py::type2str(value) + '.' + it->second; } std::string flags_str; for (const auto& [entry_value, name] : entries_map) { if (entry_value == 0) { continue; } if ((int_value & entry_value) == entry_value) { if (!flags_str.empty()) { flags_str += " | "; } if (full_type) { flags_str += LIEF::py::type2str(value) + '.' + name; } else { flags_str += name; } } } return flags_str; } template class LIEF_LOCAL enum_ : public nanobind::enum_ { public: using nanobind::enum_::def; using nanobind::enum_::def_static; using Scalar = typename std::underlying_type_t; using nanobind::class_::def_prop_ro; template enum_(const nanobind::handle &scope, const char *name, const Extra&... extra) : nanobind::enum_{scope, name, extra...} { constexpr bool is_arithmetic = (std::is_same_v || ...); /* These are methods not (yet?) implemented in nanobind */ /* ------------------------------------------------------------------------*/ def_prop_ro("value", [] (const Type &value) { return (Scalar) value; }, "The underlying integer value"); def_static("from_value", [] (Scalar i) { return static_cast(i); }); /* ------------------------------------------------------------------------*/ def("__eq__", [](const Type &value, Scalar value2) { return (Scalar) value == value2; }); def("__ne__", [](const Type &value, Scalar value2) { return (Scalar) value != value2; }); if constexpr (is_arithmetic) { def("__lt__", [](const Type &value, Scalar value2) { return (Scalar) value < value2; }); def("__gt__", [](const Type &value, Scalar value2) { return (Scalar) value > value2; }); def("__le__", [](const Type &value, Scalar value2) { return (Scalar) value <= value2; }); def("__ge__", [](const Type &value, Scalar value2) { return (Scalar) value >= value2; }); def("__invert__", [](const Type &value) { return ~((Scalar) value); }); def("__and__", [](const Type &value, Scalar value2) { return (Scalar) value & value2; }); def("__or__", [](const Type &value, Scalar value2) { return (Scalar) value | value2; }); def("__xor__", [](const Type &value, Scalar value2) { return (Scalar) value ^ value2; }); def("__rand__", [](const Type &value, Scalar value2) { return (Scalar) value & value2; }); def("__ror__", [](const Type &value, Scalar value2) { return (Scalar) value | value2; }); def("__rxor__", [](const Type &value, Scalar value2) { return (Scalar) value ^ value2; }); def("__and__", [](const Type &value, const Type &value2) { return (Scalar) value & (Scalar) value2; }); def("__or__", [](const Type &value, const Type &value2) { return Type((Scalar) value | (Scalar) value2); }); def("__xor__", [](const Type &value, const Type &value2) { return (Scalar) value ^ (Scalar) value2; }); def("__repr__", [] (const nanobind::object &value) { auto typed_value = nanobind::cast(value); auto int_value = static_cast(typed_value); return fmt::format("<{}.{}: {}>", LIEF::py::type2str(value), flag2str(value, /*full_type*/false), int_value); }); def("__str__", [] (const nanobind::object &value) { return flag2str(value, /*full_type*/true); }); } } }; } #endif