blob: ba12ed2cc2d3232c30e895823f7eee30d4641724 [file] [log] [blame]
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef INCLUDE_PERFETTO_PUBLIC_PB_MACROS_H_
#define INCLUDE_PERFETTO_PUBLIC_PB_MACROS_H_
#include "perfetto/public/compiler.h" // IWYU pragma: export
#include "perfetto/public/pb_msg.h" // IWYU pragma: export
#include "perfetto/public/pb_packed.h" // IWYU pragma: export
#include "perfetto/public/pb_utils.h" // IWYU pragma: export
// This header contains macros that define types and accessors for protobuf
// messages.
//
// Example usage:
//
// PERFETTO_PB_ENUM(perfetto_protos_BuiltinClock){
// PERFETTO_PB_ENUM_ENTRY(perfetto_protos_BUILTIN_CLOCK_UNKNOWN) = 0,
// PERFETTO_PB_ENUM_ENTRY(perfetto_protos_BUILTIN_CLOCK_REALTIME) = 1,
// PERFETTO_PB_ENUM_ENTRY(perfetto_protos_BUILTIN_CLOCK_REALTIME_COARSE)
// = 2,
// PERFETTO_PB_ENUM_ENTRY(perfetto_protos_BUILTIN_CLOCK_MONOTONIC) = 3,
// PERFETTO_PB_ENUM_ENTRY(perfetto_protos_BUILTIN_CLOCK_MONOTONIC_COARSE)
// = 4,
// PERFETTO_PB_ENUM_ENTRY(perfetto_protos_BUILTIN_CLOCK_MONOTONIC_RAW) = 5,
// PERFETTO_PB_ENUM_ENTRY(perfetto_protos_BUILTIN_CLOCK_BOOTTIME) = 6,
// PERFETTO_PB_ENUM_ENTRY(perfetto_protos_BUILTIN_CLOCK_MAX_ID) = 63,
// };
//
// PERFETTO_PB_MSG(perfetto_protos_TraceConfig_BuiltinDataSource);
// PERFETTO_PB_FIELD(perfetto_protos_TraceConfig_BuiltinDataSource,
// VARINT,
// perfetto_protos_BuiltinClock,
// primary_trace_clock,
// 5);
//
// PERFETTO_PB_MSG(perfetto_protos_TraceConfig);
// PERFETTO_PB_ENUM_IN_MSG(perfetto_protos_TraceConfig, LockdownModeOperation){
// PERFETTO_PB_ENUM_IN_MSG_ENTRY(perfetto_protos_TraceConfig,
// LOCKDOWN_UNCHANGED) = 0,
// PERFETTO_PB_ENUM_IN_MSG_ENTRY(perfetto_protos_TraceConfig,
// LOCKDOWN_CLEAR) = 1,
// PERFETTO_PB_ENUM_IN_MSG_ENTRY(perfetto_protos_TraceConfig,
// LOCKDOWN_SET) = 2,
// };
// PERFETTO_PB_FIELD(perfetto_protos_TraceConfig,
// VARINT,
// perfetto_protos_TraceConfig_LockdownModeOperation,
// lockdown_mode,
// 5);
//
// PERFETTO_PB_MSG_DECL(perfetto_protos_DebugAnnotation);
// PERFETTO_PB_MSG_DECL(perfetto_protos_TestEvent_TestPayload);
//
// PERFETTO_PB_MSG(perfetto_protos_TestEvent);
// PERFETTO_PB_FIELD(perfetto_protos_TestEvent, STRING, const char*, str, 1);
// PERFETTO_PB_FIELD(perfetto_protos_TestEvent, VARINT, uint32_t, seq_value, 2);
// PERFETTO_PB_FIELD(perfetto_protos_TestEvent, VARINT, uint64_t, counter, 3);
// PERFETTO_PB_FIELD(perfetto_protos_TestEvent,
// MSG,
// perfetto_protos_TestEvent_TestPayload,
// payload,
// 5);
//
// PERFETTO_PB_MSG(perfetto_protos_TestEvent_TestPayload);
// PERFETTO_PB_FIELD(perfetto_protos_TestEvent_TestPayload,
// STRING,
// const char*,
// str,
// 1);
// PERFETTO_PB_FIELD(perfetto_protos_TestEvent_TestPayload,
// MSG,
// perfetto_protos_DebugAnnotation,
// debug_annotations,
// 7);
#define PERFETTO_I_PB_CONCAT_4_(A, B, C, D) A##B##C##D
#define PERFETTO_I_PB_CONCAT_4(A, B, C, D) PERFETTO_I_PB_CONCAT_4_(A, B, C, D)
#define PERFETTO_I_PB_CONCAT_3_(A, B, C) A##B##C
#define PERFETTO_I_PB_CONCAT_3(A, B, C) PERFETTO_I_PB_CONCAT_3_(A, B, C)
#define PERFETTO_I_PB_SETTER_NAME(PROTO, NAME) \
PERFETTO_I_PB_CONCAT_3(PROTO, _set_, NAME)
#define PERFETTO_I_PB_SETTER_CSTR_NAME(PROTO, NAME) \
PERFETTO_I_PB_CONCAT_3(PROTO, _set_cstr_, NAME)
#define PERFETTO_I_PB_SETTER_BEGIN_NAME(PROTO, NAME) \
PERFETTO_I_PB_CONCAT_3(PROTO, _begin_, NAME)
#define PERFETTO_I_PB_SETTER_END_NAME(PROTO, NAME) \
PERFETTO_I_PB_CONCAT_3(PROTO, _end_, NAME)
#define PERFETTO_I_PB_NUM_FIELD_NAME(PROTO, NAME) \
PERFETTO_I_PB_CONCAT_4(PROTO, _, NAME, _field_number)
#define PERFETTO_I_PB_GET_MSG(C_TYPE) PERFETTO_I_PB_CONCAT_3(C_TYPE, _, get_msg)
#define PERFETTO_I_PB_FIELD_STRING(PREFIX, PROTO, C_TYPE, NAME, NUM) \
static inline void PERFETTO_I_PB_SETTER_CSTR_NAME(PREFIX, NAME)( \
struct PROTO * msg, const char* value) { \
PerfettoPbMsgAppendCStrField(&msg->msg, NUM, value); \
} \
static inline void PERFETTO_I_PB_SETTER_NAME(PREFIX, NAME)( \
struct PROTO * msg, const void* data, size_t len) { \
PerfettoPbMsgAppendType2Field( \
&msg->msg, NUM, PERFETTO_STATIC_CAST(const uint8_t*, data), len); \
} \
static inline void PERFETTO_I_PB_SETTER_BEGIN_NAME(PREFIX, NAME)( \
struct PROTO * msg, struct PerfettoPbMsg * nested) { \
PerfettoPbMsgBeginNested(&msg->msg, nested, NUM); \
} \
static inline void PERFETTO_I_PB_SETTER_END_NAME(PREFIX, NAME)( \
struct PROTO * msg, struct PerfettoPbMsg * nested) { \
(void)nested; \
PerfettoPbMsgEndNested(&msg->msg); \
}
#define PERFETTO_I_PB_FIELD_VARINT(PREFIX, PROTO, C_TYPE, NAME, NUM) \
static inline void PERFETTO_I_PB_SETTER_NAME(PREFIX, NAME)( \
struct PROTO * msg, C_TYPE value) { \
PerfettoPbMsgAppendType0Field(&msg->msg, NUM, \
PERFETTO_STATIC_CAST(uint64_t, value)); \
}
#define PERFETTO_I_PB_FIELD_ZIGZAG(PREFIX, PROTO, C_TYPE, NAME, NUM) \
static inline void PERFETTO_I_PB_SETTER_NAME(PREFIX, NAME)( \
struct PROTO * msg, C_TYPE value) { \
uint64_t encoded = \
PerfettoPbZigZagEncode64(PERFETTO_STATIC_CAST(int64_t, value)); \
PerfettoPbMsgAppendType0Field(&msg->msg, NUM, encoded); \
}
#define PERFETTO_I_PB_FIELD_FIXED64(PREFIX, PROTO, C_TYPE, NAME, NUM) \
static inline void PERFETTO_I_PB_SETTER_NAME(PREFIX, NAME)( \
struct PROTO * msg, C_TYPE value) { \
uint64_t val; \
memcpy(&val, &value, sizeof val); \
PerfettoPbMsgAppendFixed64Field(&msg->msg, NUM, val); \
}
#define PERFETTO_I_PB_FIELD_FIXED32(PREFIX, PROTO, C_TYPE, NAME, NUM) \
static inline void PERFETTO_I_PB_SETTER_NAME(PREFIX, NAME)( \
struct PROTO * msg, C_TYPE value) { \
uint32_t val; \
memcpy(&val, &value, sizeof val); \
PerfettoPbMsgAppendFixed32Field(&msg->msg, NUM, val); \
}
#define PERFETTO_I_PB_FIELD_MSG(PREFIX, PROTO, C_TYPE, NAME, NUM) \
static inline void PERFETTO_I_PB_SETTER_BEGIN_NAME(PREFIX, NAME)( \
struct PROTO * msg, struct C_TYPE * nested) { \
struct PerfettoPbMsg* nested_msg = \
PERFETTO_REINTERPRET_CAST(struct PerfettoPbMsg*, nested); \
PerfettoPbMsgBeginNested(&msg->msg, nested_msg, NUM); \
} \
static inline void PERFETTO_I_PB_SETTER_END_NAME(PREFIX, NAME)( \
struct PROTO * msg, struct C_TYPE * nested) { \
(void)nested; \
PerfettoPbMsgEndNested(&msg->msg); \
}
#define PERFETTO_I_PB_FIELD_PACKED(PREFIX, PROTO, C_TYPE, NAME, NUM) \
static inline void PERFETTO_I_PB_SETTER_NAME(PREFIX, NAME)( \
struct PROTO * msg, const void* data, size_t len) { \
PerfettoPbMsgAppendType2Field( \
&msg->msg, NUM, PERFETTO_STATIC_CAST(const uint8_t*, data), len); \
} \
static inline void PERFETTO_I_PB_SETTER_BEGIN_NAME(PREFIX, NAME)( \
struct PROTO * msg, struct PerfettoPbPackedMsg##C_TYPE * nested) { \
struct PerfettoPbMsg* nested_msg = \
PERFETTO_REINTERPRET_CAST(struct PerfettoPbMsg*, nested); \
PerfettoPbMsgBeginNested(&msg->msg, nested_msg, NUM); \
} \
static inline void PERFETTO_I_PB_SETTER_END_NAME(PREFIX, NAME)( \
struct PROTO * msg, struct PerfettoPbPackedMsg##C_TYPE * nested) { \
(void)nested; \
PerfettoPbMsgEndNested(&msg->msg); \
}
#define PERFETTO_I_PB_NUM_FIELD(PROTO, NAME, NUM) \
enum { PERFETTO_I_PB_NUM_FIELD_NAME(PROTO, NAME) = NUM }
// Below are public macros that can be used to define protos. All the macros
// above are just implementation details and can change at any time.
// Defines the type for a protobuf message.
// `PROTO` is the name of the message type. For nested messages, an underscore
// should be used as a separator.
#define PERFETTO_PB_MSG(PROTO) \
struct PROTO { \
struct PerfettoPbMsg msg; \
}
// Declares the type for a protobuf message. Useful when a file references a
// type (because it is used as type for a field), but doesn't need the full
// definition.
#define PERFETTO_PB_MSG_DECL(PROTO) struct PROTO
// Defines accessors for a field of a message.
// * `PROTO`: The message that contains this field. This should be the same
// identifier passed to PERFETTO_PB_MSG.
// * `NAME`: The name of the field. It will be concatenated with `PROTO` to
// produce the name for the accessors.
// * `NUM`: The numeric identifier for this field.
// * `TYPE`: The protobuf type of the field. Possible options:
// * `VARINT`: For most integer (scalar and repeated non-packed) and enum
// field types. `CTYPE` is the corresponding C type of the field. Generates
// a single NAMESPACE_PROTO_set_NAME(CTYPE value accessor).
// * `ZIGZAG`: For sint* (scalar and repeated non-packed) field types. `CTYPE`
// is the corresponding C type of the field. Generates a single
// PROTO_set_NAME(struct PROTO*, CTYPE) value setter.
// * `FIXED32`: For fixed32, sfixed32 and float (scalar and repeated
// non-packed) field types. `CTYPE` can be uint32_t, int32_t or float.
// Generates a single PROTO_set_NAME(struct PROTO*, CTYPE) value setter.
// * `FIXED64`: For fixed64, sfixed64 or double (scalar and repeated
// non-packed) field types. `CTYPE` can be uint64_t or int64_t or double.
// Generates a single PROTO_set_NAME(struct PROTO*, CTYPE) value setter.
// * `MSG`: for nested (scalar and repeated) messages field types. `CTYPE` is
// the type of the nested message (full type, including the namespace).
// Generates
// `PROTO_begin_NAME(struct PROTO*, struct CTYPE* nested)` and
// `PROTO_end_NAME(struct PROTO*, struct CTYPE* nested)` that allows to
// begin and end a nested submessage. `*nested` doesn't need to be
// initialized.
// * `STRING`: for bytes and string field types. `CTYPE` should be
// `const char *`. Generates multiple accessors:
// * PROTO_set_cstr_NAME(struct PROTO*, const char*): Sets the value of the
// field by copying from a null terminated string.
// * PROTO_set_NAME(struct PROTO*, const void*, size_t): Sets the value of
// the field by copying from a buffer at an address with the specified
// size.
// * PROTO_begin_NAME(struct PROTO*, struct PerfettoPbMsg* nested) and
// PROTO_end_NAME(struct PROTO*, struct PerfettoPbMsg* nested):
// Begins (and ends) a nested submessage to allow users to generate part
// of the length delimited buffer piece by piece.
// * `PACKED`: for packed repeated field types. `CTYPE` should be
// one of `PerfettoPbPacked*`. Generates multiple accessors:
// * PROTO_set_NAME(struct PROTO*, const void*, size_t): Sets the value of
// the field by copying from a buffer at an address with the specified
// size.
// * PROTO_begin_NAME(struct PROTO*, struct PerfettoPbPackedMsgCTYPE*
// nested) and
// PROTO_end_NAME(struct PROTO*, struct PerfettoPbPackedMsgCTYPE*
// nested): Begins (and ends) a packed helper nested submessage (of the
// right type) to allow users to push repeated entries one by one
// directly into the stream writer buffer.
#define PERFETTO_PB_FIELD(PROTO, TYPE, C_TYPE, NAME, NUM) \
PERFETTO_I_PB_FIELD_##TYPE(PROTO, PROTO, C_TYPE, NAME, NUM) \
PERFETTO_I_PB_NUM_FIELD(PROTO, NAME, NUM)
// Defines accessors for a field of a message for an extension.
// * `EXTENSION`: The name of the extension. it's going to be used as a prefix.
// There doesn't need to be a PERFETTO_PB_MSG definition for this.
// * `PROTO`: The (base) message that contains this field. This should be the
// same identifier passed to PERFETTO_PB_MSG.
// The rest of the params are the same as the PERFETTO_PB_FIELD macro.
#define PERFETTO_PB_EXTENSION_FIELD(EXTENSION, PROTO, TYPE, C_TYPE, NAME, NUM) \
PERFETTO_I_PB_FIELD_##TYPE(EXTENSION, PROTO, C_TYPE, NAME, NUM) \
PERFETTO_I_PB_NUM_FIELD(EXTENSION, NAME, NUM)
// Defines an enum type nested inside a message (PROTO).
#define PERFETTO_PB_ENUM_IN_MSG(PROTO, ENUM) \
enum PERFETTO_I_PB_CONCAT_3(PROTO, _, ENUM)
// Defines an entry for an enum tpye nested inside a message.
#define PERFETTO_PB_ENUM_IN_MSG_ENTRY(PROTO, NAME) \
PERFETTO_I_PB_CONCAT_3(PROTO, _, NAME)
// Defines a global enum type.
#define PERFETTO_PB_ENUM(ENUM) enum ENUM
// Defines an entry for global enum type.
#define PERFETTO_PB_ENUM_ENTRY(NAME) NAME
#endif // INCLUDE_PERFETTO_PUBLIC_PB_MACROS_H_