1 //
2 // Copyright (C) 2023 The Android Open Source Project
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 //      http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 #include <type_traits>
17 #include <vector>
18 
19 #include <fmt/core.h>
20 #include <google/protobuf/message.h>
21 #include <google/protobuf/text_format.h>
22 #include <google/protobuf/util/json_util.h>
23 
24 /* Format proto messages as textproto with {} or {:t} and json with {:j}. */
25 template <typename T>
26 struct fmt::formatter<
27     T,
28     std::enable_if_t<std::is_base_of_v<google::protobuf::Message, T>, char>> {
29  public:
30   constexpr format_parse_context::iterator parse(format_parse_context& ctx) {
31     auto it = ctx.begin();
32     for (; it != ctx.end() && *it != '}'; it++) {
33       format_ = *it;
34     }
35     return it;
36   }
37   format_context::iterator format(const T& proto, format_context& ctx) const {
38     std::string text;
39     if (format_ == 't') {
40       if (!google::protobuf::TextFormat::PrintToString(proto, &text)) {
41         return fmt::format_to(ctx.out(), "(proto format error");
42       }
43     } else if (format_ == 'j') {
44       auto result = google::protobuf::util::MessageToJsonString(proto, &text);
45       if (!result.ok()) {
46         return fmt::format_to(ctx.out(), "(json error: {})",
47                               std::string(result.ToString()));
48       }
49     } else {
50       return fmt::format_to(ctx.out(), "(unknown format specifier)");
51     }
52     return fmt::format_to(ctx.out(), "{}", text);
53   }
54 
55  private:
56   char format_ = 't';
57 };
58