Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore/Audacity CLA applies
4 : *
5 : * Copyright (C) MuseScore/Audacity and others
6 : *
7 : * This program is free software: you can redistribute it and/or modify
8 : * it under the terms of the GNU General Public License version 3 as
9 : * published by the Free Software Foundation.
10 : *
11 : * This program is distributed in the hope that it will be useful,
12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : * GNU General Public License for more details.
15 : *
16 : * You should have received a copy of the GNU General Public License
17 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 : */
19 :
20 : #pragma once
21 :
22 : #include <tuple>
23 :
24 : #include "rcommand/commandtypes.h"
25 :
26 : #include "log.h"
27 :
28 : namespace muse::rcommand {
29 : template<typename E>
30 : struct Contract;
31 :
32 : template<typename T>
33 : concept Enumeration = std::is_enum_v<std::remove_cvref_t<T> >;
34 :
35 : template<typename E>
36 : struct EnumEntry {
37 : std::string_view sval;
38 : E eval;
39 : std::string_view description;
40 : };
41 :
42 : template<typename E, std::size_t N>
43 : using Table = std::array<EnumEntry<E>, N>;
44 :
45 : template<typename E, std::size_t N>
46 : void accepts_table(const Table<E, N>&);
47 :
48 : template<typename T, typename E>
49 : concept EnumTable = requires(const std::remove_cvref_t<T>& table) {
50 : accepts_table<E>(table);
51 : };
52 :
53 : // *INDENT-OFF* // Uncrustify doesn't understand `requires`
54 : template<typename C>
55 : concept EnumContract = requires {
56 : { C::key } -> std::convertible_to<const std::string_view&>;
57 : { C::def } -> Enumeration;
58 : { C::table } -> EnumTable<std::remove_cvref_t<decltype(C::def)>>;
59 : };
60 : // *INDENT-ON*
61 :
62 : template<EnumContract C>
63 : struct BaseContract {
64 10 : static std::string str_val(decltype(C::def) eval)
65 : {
66 12 : for (const auto& row : C::table) {
67 12 : if (row.eval == eval) {
68 20 : return std::string(row.sval);
69 : }
70 : }
71 0 : UNREACHABLE;
72 : return std::string();
73 : }
74 :
75 14 : static std::optional<decltype(C::def)> enum_val(const std::string& sval)
76 : {
77 27 : for (const auto& row : C::table) {
78 25 : if (row.sval == sval) {
79 12 : return row.eval;
80 : }
81 : }
82 2 : return std::nullopt;
83 : }
84 :
85 0 : static std::pair<std::string, muse::Val> param(decltype(C::def) eval)
86 : {
87 0 : return { std::string(C::key), muse::Val(str_val(eval)) };
88 : }
89 :
90 0 : static decltype(C::def) get(const muse::rcommand::Params& params)
91 : {
92 0 : auto sval = params.at(C::key).toString();
93 0 : auto value = enum_val(sval);
94 0 : return value ? *value : C::def;
95 0 : }
96 :
97 : static void set(muse::rcommand::Params& params, decltype(C::def) eval)
98 : {
99 : params.set(param(eval));
100 : }
101 : };
102 :
103 : #define DECLARE_CONTRACT(E, C) template<> struct Contract<E> : BaseContract<C> {};
104 : }
|