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