blob: ebe6e84bdcb071c706deb229d44b03a88a0ab66b [file] [log] [blame]
Patrick Williamscbdc2832021-08-02 16:31:04 -05001#pragma once
2
Patrick Williams2544b412022-10-04 08:41:06 -05003#include <phosphor-logging/lg2/concepts.hpp>
4
Patrick Williams816eedf2021-08-26 10:13:36 -05005#include <algorithm>
Patrick Williams465ab602021-08-05 09:18:34 -05006#include <array>
Patrick Williamscbdc2832021-08-02 16:31:04 -05007#include <string_view>
8
9namespace lg2::details
10{
11
12/** A type to handle compile-time validation of header strings. */
13struct header_str
14{
15 // Hold the header string value.
16 std::string_view value;
17
18 /** Constructor which performs validation. */
19 template <typename T>
20 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 }
Patrick Williams465ab602021-08-05 09:18:34 -050040
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 }
Patrick Williamscbdc2832021-08-02 16:31:04 -050049 }
50
51 /** Cast conversion back to (const char*). */
52 operator const char*() const
53 {
54 return value.data();
55 }
56
57 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 */
71template <typename T>
72struct header_str_conversion
73{
74 using type = T;
75};
76
77/** Specialization for maybe_constexpr_string. */
78template <maybe_constexpr_string T>
79struct header_str_conversion<T>
80{
81 using type = const header_str&;
82};
83
84/** std-style _t alias for header_str_conversion. */
85template <typename T>
86using header_str_conversion_t = typename header_str_conversion<T>::type;
87
88} // namespace lg2::details