xref: /aosp_15_r20/external/perfetto/include/perfetto/tracing/traced_value.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2021 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 
17 #ifndef INCLUDE_PERFETTO_TRACING_TRACED_VALUE_H_
18 #define INCLUDE_PERFETTO_TRACING_TRACED_VALUE_H_
19 
20 #include "perfetto/base/compiler.h"
21 #include "perfetto/base/export.h"
22 #include "perfetto/base/template_util.h"
23 #include "perfetto/protozero/message.h"
24 #include "perfetto/protozero/proto_utils.h"
25 #include "perfetto/tracing/internal/checked_scope.h"
26 #include "perfetto/tracing/string_helpers.h"
27 #include "perfetto/tracing/traced_value_forward.h"
28 
29 #include <memory>
30 #include <string>
31 #include <string_view>
32 #include <type_traits>
33 #include <utility>
34 
35 namespace perfetto {
36 
37 namespace protos {
38 namespace pbzero {
39 class DebugAnnotation;
40 }
41 }  // namespace protos
42 
43 class DebugAnnotation;
44 class EventContext;
45 
46 // These classes provide a JSON-inspired way to write structed data into traces.
47 //
48 // Each TracedValue can be consumed exactly once to write a value into a trace
49 // using one of the Write* methods.
50 //
51 // Write* methods fall into two categories:
52 // - Primitive types (int, string, bool, double, etc): they just write the
53 //   provided value, consuming the TracedValue in the process.
54 // - Complex types (arrays and dicts): they consume the TracedValue and
55 //   return a corresponding scoped object (TracedArray or TracedDictionary).
56 //   This scope then can be used to write multiple items into the container:
57 //   TracedArray::AppendItem and TracedDictionary::AddItem return a new
58 //   TracedValue which then can be used to write an element of the
59 //   dictionary or array.
60 //
61 // To define how a custom class should be written into the trace, users should
62 // define one of the two following functions:
63 // - Foo::WriteIntoTrace(TracedValue) const
64 //   (preferred for code which depends on perfetto directly)
65 // - perfetto::TraceFormatTraits<T>::WriteIntoTrace(
66 //       TracedValue, const T&);
67 //   (should be used if T is defined in a library which doesn't know anything
68 //   about tracing).
69 //
70 //
71 // After defining a conversion method, the object can be used directly as a
72 // TRACE_EVENT argument:
73 //
74 // Foo foo;
75 // TRACE_EVENT("cat", "Event", "arg", foo);
76 //
77 // Examples:
78 //
79 // TRACE_EVENT("cat", "event", "params", [&](perfetto::TracedValue context)
80 // {
81 //   auto dict = std::move(context).WriteDictionary();
82 //   dict->Add("param1", param1);
83 //   dict->Add("param2", param2);
84 //   ...
85 //   dict->Add("paramN", paramN);
86 //
87 //   {
88 //     auto inner_array = dict->AddArray("inner");
89 //     inner_array->Append(value1);
90 //     inner_array->Append(value2);
91 //   }
92 // });
93 //
94 // template <typename T>
95 // TraceFormatTraits<std::optional<T>>::WriteIntoTrace(
96 //    TracedValue context, const std::optional<T>& value) {
97 //  if (!value) {
98 //    std::move(context).WritePointer(nullptr);
99 //    return;
100 //  }
101 //  perfetto::WriteIntoTrace(std::move(context), *value);
102 // }
103 //
104 // template <typename T>
105 // TraceFormatTraits<std::vector<T>>::WriteIntoTrace(
106 //    TracedValue context, const std::array<T>& value) {
107 //  auto array = std::move(context).WriteArray();
108 //  for (const auto& item: value) {
109 //    array_scope.Append(item);
110 //  }
111 // }
112 //
113 // class Foo {
114 //   void WriteIntoTrace(TracedValue context) const {
115 //     auto dict = std::move(context).WriteDictionary();
116 //     dict->Set("key", 42);
117 //     dict->Set("foo", "bar");
118 //     dict->Set("member", member_);
119 //   }
120 // }
121 namespace internal {
122 // TODO(altimin): Currently EventContext can be null due the need to support
123 // TracedValue-based serialisation with the Chrome's TraceLog. After this is
124 // gone, the second parameter should be changed to EventContext&.
125 PERFETTO_EXPORT_COMPONENT TracedValue
126 CreateTracedValueFromProto(protos::pbzero::DebugAnnotation*,
127                            EventContext* = nullptr);
128 }
129 
130 class PERFETTO_EXPORT_COMPONENT TracedValue {
131  public:
132   TracedValue(const TracedValue&) = delete;
133   TracedValue& operator=(const TracedValue&) = delete;
134   TracedValue& operator=(TracedValue&&) = delete;
135   TracedValue(TracedValue&&);
136   ~TracedValue();
137 
138   // TracedValue represents a context into which a single value can be written
139   // (either by writing it directly for primitive types, or by creating a
140   // TracedArray or TracedDictionary for the complex types). This is enforced
141   // by allowing Write* methods to be called only on rvalue references.
142 
143   void WriteInt64(int64_t value) &&;
144   void WriteUInt64(uint64_t value) &&;
145   void WriteDouble(double value) &&;
146   void WriteBoolean(bool value) &&;
147   void WriteString(const char*) &&;
148   void WriteString(const char*, size_t len) &&;
149   void WriteString(const std::string&) &&;
150   void WriteString(std::string_view) &&;
151   void WritePointer(const void* value) &&;
152   template <typename MessageType>
153   TracedProto<MessageType> WriteProto() &&;
154 
155   // Rules for writing nested dictionaries and arrays:
156   // - Only one scope (TracedArray, TracedDictionary or TracedValue) can be
157   // active at the same time. It's only allowed to call methods on the active
158   // scope.
159   // - When a scope creates a nested scope, the new scope becomes active.
160   // - When a scope is destroyed, its parent scope becomes active again.
161   //
162   // Typically users will have to create a scope only at the beginning of a
163   // conversion function and this scope should be destroyed at the end of it.
164   // TracedArray::Append and TracedDictionary::Add create, write and complete
165   // inner scopes automatically.
166 
167   // Scope which allows multiple values to be appended.
168   TracedArray WriteArray() && PERFETTO_WARN_UNUSED_RESULT;
169 
170   // Scope which allows multiple key-value pairs to be added.
171   TracedDictionary WriteDictionary() && PERFETTO_WARN_UNUSED_RESULT;
172 
173  private:
174   friend class TracedArray;
175   friend class TracedDictionary;
176   friend TracedValue internal::CreateTracedValueFromProto(
177       protos::pbzero::DebugAnnotation*,
178       EventContext*);
179 
180   static TracedValue CreateFromProto(protos::pbzero::DebugAnnotation* proto,
181                                      EventContext* event_context = nullptr);
182 
TracedValue(protos::pbzero::DebugAnnotation * annotation,EventContext * event_context,internal::CheckedScope * parent_scope)183   inline TracedValue(protos::pbzero::DebugAnnotation* annotation,
184                      EventContext* event_context,
185                      internal::CheckedScope* parent_scope)
186       : annotation_(annotation),
187         event_context_(event_context),
188         checked_scope_(parent_scope) {}
189 
190   protozero::Message* WriteProtoInternal(const char* name);
191 
192   // Temporary support for perfetto::DebugAnnotation C++ class before it's going
193   // to be replaced by TracedValue.
194   // TODO(altimin): Convert v8 to use TracedValue directly and delete it.
195   friend class DebugAnnotation;
196 
197   protos::pbzero::DebugAnnotation* const annotation_ = nullptr;
198   EventContext* const event_context_ = nullptr;
199 
200   internal::CheckedScope checked_scope_;
201 };
202 
203 template <typename MessageType>
WriteProto()204 TracedProto<MessageType> TracedValue::WriteProto() && {
205   return TracedProto<MessageType>(
206       static_cast<MessageType*>(WriteProtoInternal(MessageType::GetName())),
207       event_context_);
208 }
209 
210 class PERFETTO_EXPORT_COMPONENT TracedArray {
211  public:
212   // implicit
213   TracedArray(TracedValue);
214 
215   TracedArray(const TracedArray&) = delete;
216   TracedArray& operator=(const TracedArray&) = delete;
217   TracedArray& operator=(TracedArray&&) = delete;
218   TracedArray(TracedArray&&) = default;
219   ~TracedArray() = default;
220 
221   TracedValue AppendItem();
222 
223   template <typename T>
Append(T && value)224   void Append(T&& value) {
225     WriteIntoTracedValue(AppendItem(), std::forward<T>(value));
226   }
227 
228   TracedDictionary AppendDictionary() PERFETTO_WARN_UNUSED_RESULT;
229   TracedArray AppendArray();
230 
231  private:
232   friend class TracedValue;
233 
TracedArray(protos::pbzero::DebugAnnotation * annotation,EventContext * event_context,internal::CheckedScope * parent_scope)234   inline TracedArray(protos::pbzero::DebugAnnotation* annotation,
235                      EventContext* event_context,
236                      internal::CheckedScope* parent_scope)
237       : annotation_(annotation),
238         event_context_(event_context),
239         checked_scope_(parent_scope) {}
240 
241   protos::pbzero::DebugAnnotation* annotation_;
242   EventContext* const event_context_;
243 
244   internal::CheckedScope checked_scope_;
245 };
246 
247 class PERFETTO_EXPORT_COMPONENT TracedDictionary {
248  public:
249   // implicit
250   TracedDictionary(TracedValue);
251 
252   TracedDictionary(const TracedDictionary&) = delete;
253   TracedDictionary& operator=(const TracedDictionary&) = delete;
254   TracedDictionary& operator=(TracedDictionary&&) = delete;
255   TracedDictionary(TracedDictionary&&) = default;
256   ~TracedDictionary() = default;
257 
258   // There are two paths for writing dictionary keys: fast path for writing
259   // compile-time const, whose pointer is remains valid during the entire
260   // runtime of the program and the slow path for dynamic strings, which need to
261   // be copied.
262   // In the most common case, a string literal can be passed to `Add`/`AddItem`.
263   // In other cases, either StaticString or DynamicString declarations are
264   // needed.
265 
266   TracedValue AddItem(StaticString key);
267   TracedValue AddItem(DynamicString key);
268 
269   template <typename T>
Add(StaticString key,T && value)270   void Add(StaticString key, T&& value) {
271     WriteIntoTracedValue(AddItem(key), std::forward<T>(value));
272   }
273 
274   template <typename T>
Add(DynamicString key,T && value)275   void Add(DynamicString key, T&& value) {
276     WriteIntoTracedValue(AddItem(key), std::forward<T>(value));
277   }
278 
279   TracedDictionary AddDictionary(StaticString key);
280   TracedDictionary AddDictionary(DynamicString key);
281   TracedArray AddArray(StaticString key);
282   TracedArray AddArray(DynamicString key);
283 
284  private:
285   friend class TracedValue;
286   template <typename T>
287   friend class TracedProto;
288 
289   // Create a |TracedDictionary| which will populate the given field of the
290   // given |message|.
291   template <typename MessageType, typename FieldMetadata>
TracedDictionary(MessageType * message,FieldMetadata,EventContext * event_context,internal::CheckedScope * parent_scope)292   inline TracedDictionary(MessageType* message,
293                           FieldMetadata,
294                           EventContext* event_context,
295                           internal::CheckedScope* parent_scope)
296       : message_(message),
297         field_id_(FieldMetadata::kFieldId),
298         event_context_(event_context),
299         checked_scope_(parent_scope) {
300     static_assert(std::is_base_of<protozero::Message, MessageType>::value,
301                   "Message should be a subclass of protozero::Message");
302     static_assert(std::is_base_of<protozero::proto_utils::FieldMetadataBase,
303                                   FieldMetadata>::value,
304                   "FieldMetadata should be a subclass of FieldMetadataBase");
305     static_assert(
306         std::is_same<typename FieldMetadata::message_type, MessageType>::value,
307         "Field does not belong to this message");
308     static_assert(
309         std::is_same<typename FieldMetadata::cpp_field_type,
310                      ::perfetto::protos::pbzero::DebugAnnotation>::value,
311         "Field should be of DebugAnnotation type");
312     static_assert(
313         FieldMetadata::kRepetitionType ==
314             protozero::proto_utils::RepetitionType::kRepeatedNotPacked,
315         "Field should be non-packed repeated");
316   }
317 
318   protozero::Message* const message_;
319   const uint32_t field_id_;
320   EventContext* event_context_;
321 
322   internal::CheckedScope checked_scope_;
323 };
324 
325 namespace internal {
326 
327 // SFINAE helpers for finding a right overload to convert a given class to
328 // trace-friendly form, ordered from most to least preferred.
329 
330 constexpr int kMaxWriteImplPriority = 4;
331 
332 // If T has WriteIntoTracedValue member function, call it.
333 template <typename T>
334 decltype(std::declval<T>().WriteIntoTracedValue(std::declval<TracedValue>()),
335          void())
WriteImpl(base::priority_tag<4>,TracedValue context,T && value)336 WriteImpl(base::priority_tag<4>, TracedValue context, T&& value) {
337   value.WriteIntoTracedValue(std::move(context));
338 }
339 
340 // If T has WriteIntoTrace member function, call it.
341 template <typename T>
342 decltype(std::declval<T>().WriteIntoTrace(std::declval<TracedValue>()), void())
WriteImpl(base::priority_tag<4>,TracedValue context,T && value)343 WriteImpl(base::priority_tag<4>, TracedValue context, T&& value) {
344   value.WriteIntoTrace(std::move(context));
345 }
346 
347 // If perfetto::TraceFormatTraits<T>::WriteIntoTracedValue(TracedValue, const
348 // T&) is available, use it.
349 template <typename T>
decltype(TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTracedValue (std::declval<TracedValue> (),std::declval<T> ()),void ())350 decltype(TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTracedValue(
351              std::declval<TracedValue>(),
352              std::declval<T>()),
353          void())
354 WriteImpl(base::priority_tag<3>, TracedValue context, T&& value) {
355   TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTracedValue(
356       std::move(context), std::forward<T>(value));
357 }
358 
359 // If perfetto::TraceFormatTraits<T>::WriteIntoTrace(TracedValue, const T&)
360 // is available, use it.
361 template <typename T>
decltype(TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTrace (std::declval<TracedValue> (),std::declval<T> ()),void ())362 decltype(TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTrace(
363              std::declval<TracedValue>(),
364              std::declval<T>()),
365          void())
366 WriteImpl(base::priority_tag<3>, TracedValue context, T&& value) {
367   TraceFormatTraits<base::remove_cvref_t<T>>::WriteIntoTrace(
368       std::move(context), std::forward<T>(value));
369 }
370 
371 // If T has operator(), which takes TracedValue, use it.
372 // Very useful for lambda resolutions.
373 template <typename T>
decltype(std::declval<T> ()(std::declval<TracedValue> ()),void ())374 decltype(std::declval<T>()(std::declval<TracedValue>()), void())
375 WriteImpl(base::priority_tag<2>, TracedValue context, T&& value) {
376   std::forward<T>(value)(std::move(context));
377 }
378 
379 // If T is a container and its elements have tracing support, use it.
380 //
381 // Note: a reference to T should be passed to std::begin, otherwise
382 // for non-reference types const T& will be passed to std::begin, losing
383 // support for non-const WriteIntoTracedValue methods.
384 template <typename T>
385 typename check_traced_value_support<
386     decltype(*std::begin(std::declval<T&>()))>::type
WriteImpl(base::priority_tag<1>,TracedValue context,T && value)387 WriteImpl(base::priority_tag<1>, TracedValue context, T&& value) {
388   auto array = std::move(context).WriteArray();
389   for (auto&& item : value) {
390     array.Append(item);
391   }
392 }
393 
394 // std::underlying_type can't be used with non-enum types, so we need this
395 // indirection.
396 template <typename T, bool = std::is_enum<T>::value>
397 struct safe_underlying_type {
398   using type = typename std::underlying_type<T>::type;
399 };
400 
401 template <typename T>
402 struct safe_underlying_type<T, false> {
403   using type = T;
404 };
405 
406 template <typename T>
407 struct is_incomplete_type {
408   static constexpr bool value = sizeof(T) != 0;
409 };
410 
411 // sizeof is not available for const char[], but it's still not considered to be
412 // an incomplete type for our purposes as the size can be determined at runtime
413 // due to strings being null-terminated.
414 template <>
415 struct is_incomplete_type<const char[]> {
416   static constexpr bool value = true;
417 };
418 
419 }  // namespace internal
420 
421 // Helper template to determine if a given type can be passed to
422 // perfetto::WriteIntoTracedValue. These templates will fail to resolve if the
423 // class does not have it support, so they are useful in SFINAE and in producing
424 // helpful compiler results.
425 template <typename T, class Result = void>
426 using check_traced_value_support_t = decltype(
427     internal::WriteImpl(
428         std::declval<base::priority_tag<internal::kMaxWriteImplPriority>>(),
429         std::declval<TracedValue>(),
430         std::declval<T>()),
431     std::declval<Result>());
432 
433 // check_traced_value_support<T, V>::type is defined (and equal to V) iff T
434 // supports being passed to WriteIntoTracedValue. See the comment in
435 // traced_value_forward.h for more details.
436 template <typename T, class Result>
437 struct check_traced_value_support<T,
438                                   Result,
439                                   check_traced_value_support_t<T, Result>> {
440   static_assert(
441       internal::is_incomplete_type<T>::value,
442       "perfetto::TracedValue should not be used with incomplete types");
443 
444   static constexpr bool value = true;
445   using type = Result;
446 };
447 
448 namespace internal {
449 
450 // Helper class to check if a given type can be passed to
451 // perfetto::WriteIntoTracedValue. This template will always resolve (with
452 // |value| being set to either true or false depending on presence of the
453 // support, so this macro is useful in the situation when you want to e.g. OR
454 // the result with some other conditions.
455 //
456 // In this case, compiler will not give you the full deduction chain, so, for
457 // example, use check_traced_value_support for writing positive static_asserts
458 // and has_traced_value_support for writing negative.
459 template <typename T>
460 class has_traced_value_support {
461   using Yes = char[1];
462   using No = char[2];
463 
464   template <typename V>
465   static Yes& check_support(check_traced_value_support_t<V, int>);
466   template <typename V>
467   static No& check_support(...);
468 
469  public:
470   static constexpr bool value = sizeof(Yes) == sizeof(check_support<T>(0));
471 };
472 
473 }  // namespace internal
474 
475 template <typename T>
476 void WriteIntoTracedValue(TracedValue context, T&& value) {
477   // TODO(altimin): Add a URL to documentation and a list of common failure
478   // patterns.
479   static_assert(
480       internal::has_traced_value_support<T>::value,
481       "The provided type (passed to TRACE_EVENT argument / TracedArray::Append "
482       "/ TracedDictionary::Add) does not support being written in a trace "
483       "format. Please see the comment in traced_value.h for more details.");
484 
485   // Should be kept in sync with check_traced_value_support_t!
486   internal::WriteImpl(base::priority_tag<internal::kMaxWriteImplPriority>(),
487                       std::move(context), std::forward<T>(value));
488 }
489 
490 // Helpers to write a given value into TracedValue even if the given type
491 // doesn't support conversion (in which case the provided fallback should be
492 // used). Useful for automatically generating conversions for autogenerated
493 // code, but otherwise shouldn't be used as non-autogenerated code is expected
494 // to define WriteIntoTracedValue convertor.
495 // See WriteWithFallback test in traced_value_unittest.cc for a concrete
496 // example.
497 template <typename T>
498 typename std::enable_if<internal::has_traced_value_support<T>::value>::type
499 WriteIntoTracedValueWithFallback(TracedValue context,
500                                  T&& value,
501                                  const std::string&) {
502   WriteIntoTracedValue(std::move(context), std::forward<T>(value));
503 }
504 
505 template <typename T>
506 typename std::enable_if<!internal::has_traced_value_support<T>::value>::type
507 WriteIntoTracedValueWithFallback(TracedValue context,
508                                  T&&,
509                                  const std::string& fallback) {
510   std::move(context).WriteString(fallback);
511 }
512 
513 // TraceFormatTraits implementations for primitive types.
514 
515 // Specialisation for signed integer types (note: it excludes enums, which have
516 // their own explicit specialisation).
517 template <typename T>
518 struct TraceFormatTraits<
519     T,
520     typename std::enable_if<std::is_integral<T>::value &&
521                             !std::is_same<T, bool>::value &&
522                             std::is_signed<T>::value>::type> {
523   inline static void WriteIntoTrace(TracedValue context, T value) {
524     std::move(context).WriteInt64(value);
525   }
526 };
527 
528 // Specialisation for unsigned integer types (note: it excludes enums, which
529 // have their own explicit specialisation).
530 template <typename T>
531 struct TraceFormatTraits<
532     T,
533     typename std::enable_if<std::is_integral<T>::value &&
534                             !std::is_same<T, bool>::value &&
535                             std::is_unsigned<T>::value>::type> {
536   inline static void WriteIntoTrace(TracedValue context, T value) {
537     std::move(context).WriteUInt64(value);
538   }
539 };
540 
541 // Specialisation for bools.
542 template <>
543 struct TraceFormatTraits<bool> {
544   inline static void WriteIntoTrace(TracedValue context, bool value) {
545     std::move(context).WriteBoolean(value);
546   }
547 };
548 
549 // Specialisation for floating point values.
550 template <typename T>
551 struct TraceFormatTraits<
552     T,
553     typename std::enable_if<std::is_floating_point<T>::value>::type> {
554   inline static void WriteIntoTrace(TracedValue context, T value) {
555     std::move(context).WriteDouble(static_cast<double>(value));
556   }
557 };
558 
559 // Specialisation for signed enums.
560 template <typename T>
561 struct TraceFormatTraits<
562     T,
563     typename std::enable_if<
564         std::is_enum<T>::value &&
565         std::is_signed<
566             typename internal::safe_underlying_type<T>::type>::value>::type> {
567   inline static void WriteIntoTrace(TracedValue context, T value) {
568     std::move(context).WriteInt64(static_cast<int64_t>(value));
569   }
570 };
571 
572 // Specialisation for unsigned enums.
573 template <typename T>
574 struct TraceFormatTraits<
575     T,
576     typename std::enable_if<
577         std::is_enum<T>::value &&
578         std::is_unsigned<
579             typename internal::safe_underlying_type<T>::type>::value>::type> {
580   inline static void WriteIntoTrace(TracedValue context, T value) {
581     std::move(context).WriteUInt64(static_cast<uint64_t>(value));
582   }
583 };
584 
585 // Specialisations for C-style strings.
586 template <>
587 struct TraceFormatTraits<const char*> {
588   inline static void WriteIntoTrace(TracedValue context, const char* value) {
589     std::move(context).WriteString(value);
590   }
591 };
592 
593 template <>
594 struct TraceFormatTraits<char[]> {
595   inline static void WriteIntoTrace(TracedValue context, const char value[]) {
596     std::move(context).WriteString(value);
597   }
598 };
599 
600 template <size_t N>
601 struct TraceFormatTraits<char[N]> {
602   inline static void WriteIntoTrace(TracedValue context, const char value[N]) {
603     std::move(context).WriteString(value);
604   }
605 };
606 
607 // Specialization for Perfetto strings.
608 template <>
609 struct TraceFormatTraits<perfetto::StaticString> {
610   inline static void WriteIntoTrace(TracedValue context,
611                                     perfetto::StaticString str) {
612     std::move(context).WriteString(str.value);
613   }
614 };
615 
616 template <>
617 struct TraceFormatTraits<perfetto::DynamicString> {
618   inline static void WriteIntoTrace(TracedValue context,
619                                     perfetto::DynamicString str) {
620     std::move(context).WriteString(str.value, str.length);
621   }
622 };
623 
624 // Specialisation for C++ strings.
625 template <>
626 struct TraceFormatTraits<std::string> {
627   inline static void WriteIntoTrace(TracedValue context,
628                                     const std::string& value) {
629     std::move(context).WriteString(value);
630   }
631 };
632 
633 // Specialisation for C++ string_views.
634 template <>
635 struct TraceFormatTraits<std::string_view> {
636   inline static void WriteIntoTrace(TracedValue context,
637                                     std::string_view value) {
638     std::move(context).WriteString(value);
639   }
640 };
641 
642 // Specialisation for (const) void*, which writes the pointer value.
643 template <>
644 struct TraceFormatTraits<void*> {
645   inline static void WriteIntoTrace(TracedValue context, void* value) {
646     std::move(context).WritePointer(value);
647   }
648 };
649 
650 template <>
651 struct TraceFormatTraits<const void*> {
652   inline static void WriteIntoTrace(TracedValue context, const void* value) {
653     std::move(context).WritePointer(value);
654   }
655 };
656 
657 // Specialisation for std::unique_ptr<>, which writes either nullptr or the
658 // object it points to.
659 template <typename T>
660 struct TraceFormatTraits<std::unique_ptr<T>, check_traced_value_support_t<T>> {
661   inline static void WriteIntoTrace(TracedValue context,
662                                     const std::unique_ptr<T>& value) {
663     ::perfetto::WriteIntoTracedValue(std::move(context), value.get());
664   }
665 
666   template <typename MessageType>
667   inline static void WriteIntoTrace(TracedProto<MessageType> message,
668                                     const std::unique_ptr<T>& value) {
669     ::perfetto::WriteIntoTracedProto(std::move(message), value.get());
670   }
671 };
672 
673 // Specialisation for raw pointer, which writes either nullptr or the object it
674 // points to.
675 template <typename T>
676 struct TraceFormatTraits<T*, check_traced_value_support_t<T>> {
677   inline static void WriteIntoTrace(TracedValue context, T* value) {
678     if (!value) {
679       std::move(context).WritePointer(nullptr);
680       return;
681     }
682     ::perfetto::WriteIntoTracedValue(std::move(context), *value);
683   }
684 
685   template <typename MessageType>
686   inline static void WriteIntoTrace(TracedProto<MessageType> message,
687                                     T* value) {
688     if (!value) {
689       // Start the message, but do not write anything. TraceProcessor will emit
690       // a NULL value.
691       return;
692     }
693 
694     ::perfetto::WriteIntoTracedProto(std::move(message), *value);
695   }
696 };
697 
698 // Specialisation for nullptr.
699 template <>
700 struct TraceFormatTraits<std::nullptr_t> {
701   inline static void WriteIntoTrace(TracedValue context, std::nullptr_t) {
702     std::move(context).WritePointer(nullptr);
703   }
704 
705   template <typename MessageType>
706   inline static void WriteIntoTrace(TracedProto<MessageType>, std::nullptr_t) {
707     // Start the message, but do not write anything. TraceProcessor will emit a
708     // NULL value.
709   }
710 };
711 
712 }  // namespace perfetto
713 
714 #endif  // INCLUDE_PERFETTO_TRACING_TRACED_VALUE_H_
715