1 #pragma once
2 
3 #include <phosphor-logging/lg2/concepts.hpp>
4 
5 #include <algorithm>
6 #include <array>
7 #include <string_view>
8 
9 namespace lg2::details
10 {
11 
12 /** A type to handle compile-time validation of header strings. */
13 struct header_str
14 {
15     // Hold the header string value.
16     std::string_view value;
17 
18     /** Constructor which performs validation. */
19     template <typename T>
header_strlg2::details::header_str20     consteval header_str(const T& s) : value(s)
21     {
22         if (value.size() == 0)
23         {
24             report_error(
25                 "journald requires headers must have non-zero length.");
26         }
27         if (value[0] == '_')
28         {
29             report_error("journald requires header do not start with "
30                          "underscore (_)");
31         }
32 
33         if (value.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZ_0123456789") !=
34             std::string_view::npos)
35         {
36             report_error(
37                 "journald requires header may only contain underscore, "
38                 "uppercase letters, or numbers ([_A-Z0-9]).");
39         }
40 
41         constexpr std::array reserved{
42             "CODE_FILE",   "CODE_FUNC", "CODE_LINE",
43             "LOG2_FMTMSG", "MESSAGE",   "PRIORITY",
44         };
45         if (std::ranges::find(reserved, value) != std::end(reserved))
46         {
47             report_error("Header name is reserved.");
48         }
49     }
50 
51     /** Cast conversion back to (const char*). */
operator const char*lg2::details::header_str52     operator const char*() const
53     {
54         return value.data();
55     }
56 
datalg2::details::header_str57     const char* data() const
58     {
59         return value.data();
60     }
61 
62   private:
63     // This does nothing, but is useful for creating nice compile errors in
64     // a constexpr context.
65     static void report_error(const char*);
66 };
67 
68 /** A helper type for constexpr conversion into header_str, if
69  *  'maybe_constexpr_string'.  For non-constexpr string, this does nothing.
70  */
71 template <typename T>
72 struct header_str_conversion
73 {
74     using type = T;
75 };
76 
77 /** Specialization for maybe_constexpr_string. */
78 template <maybe_constexpr_string T>
79 struct header_str_conversion<T>
80 {
81     using type = const header_str&;
82 };
83 
84 /** std-style _t alias for header_str_conversion. */
85 template <typename T>
86 using header_str_conversion_t = typename header_str_conversion<T>::type;
87 
88 } // namespace lg2::details
89