1#pragma once
2#include <algorithm>
3#include <array>
4#include <optional>
5#include <string>
6#include <string_view>
7#include <tuple>
8
9#include <sdbusplus/exception.hpp>
10#include <sdbusplus/message.hpp>
11#include <sdbusplus/utility/dedup_variant.hpp>
12<%
13    def setOfPropertyTypes():
14        return set(p.cppTypeParam(interface.name) for p in
15                   interface.properties);
16%>\
17
18namespace sdbusplus::common::${interface.cppNamespace()}
19{
20
21struct ${interface.classname}
22{
23    static constexpr auto interface = "${interface.name}";
24
25    % for e in interface.enums:
26    enum class ${e.name}
27    {
28        % for v in e.values:
29        ${v.name},
30        % endfor
31    };
32    % endfor
33
34    % if interface.properties:
35    using PropertiesVariant = sdbusplus::utility::dedup_variant_t<
36        ${",\n        ".join(sorted(setOfPropertyTypes()))}>;
37    % endif \
38
39    % for p in interface.paths:
40        % if p.description:
41    /** ${p.description.strip()} */
42        % endif
43        % if len(p.segments) == 0:
44    static constexpr auto ${p.snake_case} = "${p.value}";
45        % else:
46    struct ${p.snake_case}
47    {
48        static constexpr auto value = "${p.value}";
49            % for s in p.segments:
50                % if s.description:
51        /** ${s.description.strip()} */
52                % endif
53        static constexpr auto ${s.snake_case} = "${s.value}";
54            % endfor
55    };
56        % endif
57    % endfor
58    % for s in interface.service_names:
59        % if s.description:
60    /** ${s.description.strip()} */
61        % endif
62    static constexpr auto ${s.snake_case} = "${s.value}";
63    % endfor
64
65    % for e in interface.enums:
66    /** @brief Convert a string to an appropriate enum value.
67     *  @param[in] s - The string to convert in the form of
68     *                 "${interface.name}.<value name>"
69     *  @return - The enum value.
70     *
71     *  @note Throws if string is not a valid mapping.
72     */
73    static ${e.name} convert${e.name}FromString(const std::string& s);
74
75    /** @brief Convert a string to an appropriate enum value.
76     *  @param[in] s - The string to convert in the form of
77     *                 "${interface.name}.<value name>"
78     *  @return - The enum value or std::nullopt
79     */
80    static std::optional<${e.name}>
81        convertStringTo${e.name}(const std::string& s) noexcept;
82
83    /** @brief Convert an enum value to a string.
84     *  @param[in] e - The enum to convert to a string.
85     *  @return - The string conversion in the form of
86     *            "${interface.name}.<value name>"
87     */
88    static std::string convert${e.name}ToString(${e.name} e);
89    % endfor
90};
91
92% for e in interface.enums:
93/* Specialization of sdbusplus::common::convertForMessage
94 * for enum-type ${interface.classname}::${e.name}.
95 *
96 * This converts from the enum to a constant string representing the enum.
97 *
98 * @param[in] e - Enum value to convert.
99 * @return string representing the name for the enum value.
100 */
101inline std::string convertForMessage(${interface.classname}::${e.name} e)
102{
103    return ${interface.classname}::convert${e.name}ToString(e);
104}
105% endfor
106
107    % for e in interface.enums:
108
109namespace details
110{
111using namespace std::literals::string_view_literals;
112
113/** String to enum mapping for ${interface.classname}::${e.name} */
114inline constexpr std::array mapping${interface.classname}${e.name} = {
115    % for v in e.values:
116    std::make_tuple("${interface.name}.${e.name}.${v.name}"sv,
117                    ${interface.classname}::${e.name}::${v.name} ),
118    % endfor
119};
120} //  namespace details
121
122inline auto ${interface.classname}::convertStringTo${e.name}(const std::string& s) noexcept
123    -> std::optional<${e.name}>
124{
125    auto i = std::find_if(std::begin(details::mapping${interface.classname}${e.name}),
126                          std::end(details::mapping${interface.classname}${e.name}),
127                          [&s](auto& e){ return s == std::get<0>(e); } );
128
129    if (std::end(details::mapping${interface.classname}${e.name}) == i)
130    {
131        return std::nullopt;
132    }
133    else
134    {
135        return std::get<1>(*i);
136    }
137}
138
139inline auto ${interface.classname}::convert${e.name}FromString(const std::string& s) -> ${e.name}
140{
141    auto r = convertStringTo${e.name}(s);
142
143    if (!r)
144    {
145        throw sdbusplus::exception::InvalidEnumString();
146    }
147    else
148    {
149        return *r;
150    }
151}
152
153inline std::string ${interface.classname}::convert${e.name}ToString(
154    ${interface.classname}::${e.name} v)
155{
156    auto i = std::find_if(std::begin(details::mapping${interface.classname}${e.name}),
157                          std::end(details::mapping${interface.classname}${e.name}),
158                          [v](auto& e){ return v == std::get<1>(e); });
159
160    if (i == std::end(details::mapping${interface.classname}${e.name}))
161    {
162        throw std::invalid_argument(std::to_string(static_cast<int>(v)));
163    }
164    return std::string(std::get<0>(*i));
165}
166    % endfor
167
168} // sdbusplus::common::${interface.cppNamespace()}
169
170namespace sdbusplus::message::details
171{
172    % for e in interface.enums:
173template <>
174struct convert_from_string<common::${interface.cppNamespacedClass()}::${e.name}>
175{
176    static auto op(const std::string& value) noexcept
177    {
178        return common::${interface.cppNamespacedClass()}::
179            convertStringTo${e.name}(value);
180    }
181};
182
183template <>
184struct convert_to_string<common::${interface.cppNamespacedClass()}::${e.name}>
185{
186    static std::string
187        op(common::${interface.cppNamespacedClass()}::${e.name} value)
188    {
189        return common::${interface.cppNamespacedClass()}::
190            convert${e.name}ToString(value);
191    }
192};
193    % endfor
194} // namespace sdbusplus::message::details
195