// SPDX-FileCopyrightText: 2025 Contributors to Chatterino // // SPDX-License-Identifier: MIT #pragma once #include "util/QMagicEnum.hpp" #include namespace chatterino::qmagicenum { using customize_t = std::optional; namespace detail { namespace tag { struct DisplayName { }; } // namespace tag /// Builds the tagged data for a specific enum value (V), type (E), and Tag. /// /// If the Tag is DisplayName, attempts to obtain a custom display name for the enum value V by calling /// qmagicenumDisplayName(V). If no customization is provided, falls back to magic_enum's name for the value. /// /// @tparam E Enum type /// @tparam Tag Tag type (e.g. DisplayName) /// @tparam V Enum value /// @returns A compile-time static string containing the tagged data for the enum value template constexpr auto buildEnumValueTaggedData() noexcept { [[maybe_unused]] constexpr auto custom = [] { static_assert( std::is_same_v, "unhandled tag in QMagicEnumTagged.hpp::enumTaggedDataValue"); if constexpr (std::is_same_v) { return qmagicenumDisplayName(V); } }(); if constexpr (custom.has_value()) { constexpr auto name = *custom; static_assert(!name.empty(), "qmagicenum::customize must return a non-empty string."); return magic_enum::detail::static_str{name}; } else { // No specialization for this enum value; fall back to magic_enum's value name return magic_enum::detail::enum_name_v; } } /// Stores a static std::string_view for each (enum value, Tag) pair. /// /// For example, for MyEnum { Foo, Bar } and DisplayName tag, this will generate: /// TAGGED_DATA_STORAGE_MyEnum_DisplayName_Foo = "Custom display name for Foo" /// TAGGED_DATA_STORAGE_MyEnum_DisplayName_Bar = "Custom display name for Bar" template inline constexpr auto TAGGED_DATA_STORAGE = buildEnumValueTaggedData(); /// Converts the static string representation of an enum value + tag into a std::array template consteval auto enumTaggedDataStorage() { constexpr std::string_view utf8 = TAGGED_DATA_STORAGE; static_assert(isLatin1(utf8), "Can't convert non-latin1 UTF8 to UTF16"); std::array storage; for (std::size_t i = 0; i < utf8.size(); i++) { storage[i] = static_cast(utf8[i]); } storage[utf8.size()] = 0; return storage; } /// Stores a std::array for each (enum value, Tag) pair. /// /// For example, for MyEnum { Foo, Bar } and DisplayName tag, this will generate: /// TAGGED_DATA_MyEnum_DisplayName_Foo = "Custom display name for Foo" (char16_t array) /// TAGGED_DATA_MyEnum_DisplayName_Bar = "Custom display name for Bar" (char16_t array) template inline constexpr auto TAGGED_DATA = enumTaggedDataStorage(); /// Builds a std::array for an enum type and tag, holding the tagged data for each enum value. /// /// For example, for MyEnum { Foo, Bar } and DisplayName tag, this will generate: /// INDEXED_DATA_STORAGE_MyEnum_DisplayName[0] = "Custom display name for Foo" /// INDEXED_DATA_STORAGE_MyEnum_DisplayName[1] = "Custom display name for Bar" template consteval auto taggedDataStorage(std::index_sequence /*unused*/) { return std::array{{detail::fromArray( TAGGED_DATA()[I]>)...}}; } /// Stores a std::array for a given enum type and tag, allowing indexed access to tagged data. /// /// For example, for MyEnum { Foo, Bar } and DisplayName tag, this will generate: /// INDEXED_TAGGED_DATA_MyEnum_DisplayName[0] = "Custom display name for Foo" /// INDEXED_TAGGED_DATA_MyEnum_DisplayName[1] = "Custom display name for Bar" template inline constexpr auto INDEXED_TAGGED_DATA = taggedDataStorage( std::make_index_sequence()>{}); /// Get the tagged data for a specific enum value and tag at compile time. /// /// @tparam V Enum value /// @tparam Tag Tag type /// @returns The tagged data as a QStringView for the enum value. template [[nodiscard]] consteval QStringView enumTaggedData() noexcept { return QStringView{ detail::fromArray(detail::TAGGED_DATA)}; } /// Get the tagged data for a runtime enum value and tag. /// /// @tparam Tag Tag type /// @param value Enum value /// @returns The tagged data as a QStringView for the enum value, or an empty view if value is invalid. template [[nodiscard]] constexpr QStringView enumTaggedData(E value) noexcept { using D = std::decay_t; if (const auto i = magic_enum::enum_index(value)) { return detail::INDEXED_TAGGED_DATA[*i]; } return {}; } } // namespace detail /// Get the display name of a specific enum value as a QStringView at compile time. /// /// If the enum type provides a qmagicenumDisplayName specialization, it is used. Otherwise, fall back to magic_enum's name. /// /// @tparam V Enum value /// @returns Display name as QStringView, or name as fallback. template [[nodiscard]] consteval QStringView enumDisplayName() noexcept { if constexpr (requires { qmagicenumDisplayName(V); }) { return detail::enumTaggedData(); } // Fall back to our qmagicenum "enum name" implementation return enumName(); } /// Get the display name of a runtime enum value as a QStringView. /// /// If the enum type provides a qmagicenumDisplayName specialization, it is used. Otherwise, fall back to magic_enum's name. /// /// @param value Enum value /// @returns Display name as QStringView, or name as fallback, or an empty string if not available. template [[nodiscard]] constexpr QStringView enumDisplayName(E value) noexcept { if constexpr (requires { qmagicenumDisplayName(value); }) { using D = std::decay_t; return detail::enumTaggedData(value); } // Fall back to our qmagicenum "enum name" implementation return enumName(value); } /// Get the display name of a specific enum value as a static QString. /// /// If the enum type provides a qmagicenumDisplayName specialization, it is used. Otherwise, fall back to magic_enum's name. /// /// @tparam V Enum value /// @returns Display name as QString. The returned string is static. template [[nodiscard]] inline QString enumDisplayNameString() noexcept { return detail::staticString(enumDisplayName()); } /// Get the display name of a runtime enum value as a static QString. /// /// If the enum type provides a qmagicenumDisplayName specialization, it is used. Otherwise, fall back to magic_enum's name. /// /// @param value Enum value /// @returns Display name as QString. Returns an empty string if value is invalid. The returned string is static. template [[nodiscard]] inline QString enumDisplayNameString(E value) noexcept { using D = std::decay_t; return detail::staticString(enumDisplayName(value)); } } // namespace chatterino::qmagicenum