1 /* 2 * Copyright (c) Facebook, Inc. and its affiliates. 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 17 #ifndef THRIFT_FATAL_PRETTY_PRINT_INL_POST_H_ 18 #define THRIFT_FATAL_PRETTY_PRINT_INL_POST_H_ 1 19 20 #include <fatal/type/enum.h> 21 #include <fatal/type/search.h> 22 #include <fatal/type/variant_traits.h> 23 #include <folly/String.h> 24 25 namespace apache { 26 namespace thrift { 27 namespace detail { 28 29 /** 30 * Pretty print specialization for enumerations. 31 * 32 * @author: Marcelo Juchem <marcelo@fb.com> 33 */ 34 template <> 35 struct pretty_print_impl<type_class::enumeration> { 36 template <typename OutputStream, typename T> 37 static void print(OutputStream& out, T const& what) { 38 out << fatal::enum_to_string(what, nullptr); 39 } 40 }; 41 42 /** 43 * Pretty print specialization for lists. 44 * 45 * @author: Marcelo Juchem <marcelo@fb.com> 46 */ 47 template <typename ValueTypeClass> 48 struct pretty_print_impl<type_class::list<ValueTypeClass>> { 49 template <typename OutputStream, typename T> 50 static void print(OutputStream& out, T const& what) { 51 out << "<list>["; 52 if (!what.empty()) { 53 out.newline(); 54 auto const size = what.size(); 55 std::size_t index = 0; 56 for (auto const& i : what) { 57 auto scope = out.start_scope(); 58 scope << index << ": "; 59 pretty_print_impl<ValueTypeClass>::print(scope, i); 60 if (++index < size) { 61 scope << ','; 62 } 63 scope.newline(); 64 } 65 } 66 out << ']'; 67 } 68 }; 69 70 /** 71 * Pretty print specialization for maps. 72 * 73 * @author: Marcelo Juchem <marcelo@fb.com> 74 */ 75 template <typename KeyTypeClass, typename MappedTypeClass> 76 struct pretty_print_impl<type_class::map<KeyTypeClass, MappedTypeClass>> { 77 template <typename OutputStream, typename T> 78 static void print(OutputStream& out, T const& what) { 79 out << "<map>{"; 80 if (!what.empty()) { 81 out.newline(); 82 auto const size = what.size(); 83 std::size_t index = 0; 84 for (auto const& i : what) { 85 auto scope = out.start_scope(); 86 pretty_print_impl<KeyTypeClass>::print(scope, i.first); 87 scope << ": "; 88 pretty_print_impl<MappedTypeClass>::print(scope, i.second); 89 if (++index < size) { 90 scope << ','; 91 } 92 scope.newline(); 93 } 94 } 95 out << '}'; 96 } 97 }; 98 99 /** 100 * Pretty print specialization for sets. 101 * 102 * @author: Marcelo Juchem <marcelo@fb.com> 103 */ 104 template <typename ValueTypeClass> 105 struct pretty_print_impl<type_class::set<ValueTypeClass>> { 106 template <typename OutputStream, typename T> 107 static void print(OutputStream& out, T const& what) { 108 out << "<set>{"; 109 if (!what.empty()) { 110 out.newline(); 111 auto const size = what.size(); 112 std::size_t index = 0; 113 for (auto const& i : what) { 114 auto scope = out.start_scope(); 115 pretty_print_impl<ValueTypeClass>::print(scope, i); 116 if (++index < size) { 117 scope << ','; 118 } 119 scope.newline(); 120 } 121 } 122 out << '}'; 123 } 124 }; 125 126 /** 127 * Thrift structures and unions may contain members that are wrapped in smart 128 * pointers. This class helps decode those. 129 */ 130 struct pretty_print_structure_with_pointers { 131 protected: 132 template <typename TypeClass, typename OutputStream, typename T> 133 static void recurse_into(OutputStream& out, T const& member) { 134 pretty_print_impl<TypeClass>::print(out, member); 135 } 136 137 template <typename TypeClass, typename OutputStream, typename T> 138 static void recurse_into_ptr(OutputStream& out, T const* pMember) { 139 if (!pMember) { 140 out << "null"; 141 return; 142 } 143 recurse_into<TypeClass>(out, *pMember); 144 } 145 146 template <typename TypeClass, typename OutputStream, typename T> 147 static void recurse_into( 148 OutputStream& out, 149 optional_boxed_field_ref<boxed_value_ptr<T> const&> pMember) { 150 return recurse_into_ptr<TypeClass>(out, pMember ? &*pMember : nullptr); 151 } 152 153 template <typename TypeClass, typename OutputStream, typename T> 154 static void recurse_into( 155 OutputStream& out, std::shared_ptr<T> const& pMember) { 156 return recurse_into_ptr<TypeClass>(out, pMember.get()); 157 } 158 159 template <typename TypeClass, typename OutputStream, typename T> 160 static void recurse_into( 161 OutputStream& out, std::unique_ptr<T> const& pMember) { 162 return recurse_into_ptr<TypeClass>(out, pMember.get()); 163 } 164 }; 165 166 /** 167 * Pretty print specialization for variants (Thrift unions). 168 * 169 * @author: Marcelo Juchem <marcelo@fb.com> 170 */ 171 template <> 172 struct pretty_print_impl<type_class::variant> 173 : pretty_print_structure_with_pointers { 174 template <typename OutputStream, typename T> 175 static void print(OutputStream& out, T const& what) { 176 using descriptors = typename fatal::variant_traits<T>::descriptors; 177 out << "<variant>{"; 178 using key = fatal::get_type::id; 179 fatal::scalar_search<descriptors, key>(what.getType(), [&](auto indexed) { 180 using descriptor = decltype(fatal::tag_type(indexed)); 181 auto scope = out.start_scope(); 182 scope.newline(); 183 scope << fatal::enum_to_string(what.getType(), nullptr) << ": "; 184 recurse_into<typename descriptor::metadata::type_class>( 185 scope, typename descriptor::getter()(what)); 186 scope.newline(); 187 }); 188 out << '}'; 189 } 190 }; 191 192 /* 193 * Pretty print specialization for structures. 194 * 195 * @author: Marcelo Juchem <marcelo@fb.com> 196 */ 197 template <> 198 struct pretty_print_impl<type_class::structure> 199 : pretty_print_structure_with_pointers { 200 template <typename OutputStream, typename T> 201 static void print(OutputStream& out, T const& what) { 202 out << "<struct>{"; 203 out.newline(); 204 using info = reflect_struct<T>; 205 fatal::foreach<typename info::members>([&](auto indexed) { 206 constexpr auto size = fatal::size<typename info::members>::value; 207 using member = decltype(fatal::tag_type(indexed)); 208 if (member::optional::value == optionality::optional && 209 !member::is_set(what)) { 210 return; 211 } 212 auto const index = fatal::tag_index(indexed); 213 auto scope = out.start_scope(); 214 scope << fatal::z_data<typename member::name>() << ": "; 215 recurse_into<typename member::type_class>( 216 scope, typename member::getter{}(what)); 217 if (index + 1 < size) { 218 scope << ','; 219 } 220 scope.newline(); 221 }); 222 out << '}'; 223 } 224 }; 225 226 /** 227 * Pretty print specialization for strings. 228 * 229 * @author: Marcelo Juchem <marcelo@fb.com> 230 */ 231 template <> 232 struct pretty_print_impl<type_class::string> { 233 template <typename OutputStream, typename T> 234 static void print(OutputStream& out, T const& what) { 235 out << '"' << folly::cEscape<T>(what) << '"'; 236 } 237 }; 238 239 /** 240 * Pretty print fallback specialization. 241 * 242 * @author: Marcelo Juchem <marcelo@fb.com> 243 */ 244 template <typename> 245 struct pretty_print_impl { 246 template <typename OutputStream, typename T> 247 static void print(OutputStream& out, T const& what) { 248 out << what; 249 } 250 251 template <typename OutputStream> 252 static void print(OutputStream& out, bool const what) { 253 out << (what ? "true" : "false"); 254 } 255 }; 256 257 } // namespace detail 258 } // namespace thrift 259 } // namespace apache 260 261 #endif // THRIFT_FATAL_PRETTY_PRINT_INL_POST_H_ 262