1 // Copyright 2024 The Abseil Authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // -----------------------------------------------------------------------------
16 // File: log/internal/structured_proto.h
17 // -----------------------------------------------------------------------------
18
19 #ifndef ABSL_LOG_INTERNAL_STRUCTURED_PROTO_H_
20 #define ABSL_LOG_INTERNAL_STRUCTURED_PROTO_H_
21
22 #include <cstddef>
23 #include <cstdint>
24
25 #include "absl/base/config.h"
26 #include "absl/log/internal/proto.h"
27 #include "absl/types/span.h"
28 #include "absl/types/variant.h"
29
30 namespace absl {
31 ABSL_NAMESPACE_BEGIN
32 namespace log_internal {
33
34 // Sum type holding a single valid protobuf field suitable for encoding.
35 struct StructuredProtoField final {
36 // Numeric type encoded with varint encoding:
37 // https://protobuf.dev/programming-guides/encoding/#varints
38 using Varint = absl::variant<uint64_t, int64_t, uint32_t, int32_t, bool>;
39
40 // Fixed-length 64-bit integer encoding:
41 // https://protobuf.dev/programming-guides/encoding/#non-varints
42 using I64 = absl::variant<uint64_t, int64_t, double>;
43
44 // Length-delimited record type (string, sub-message):
45 // https://protobuf.dev/programming-guides/encoding/#length-types
46 using LengthDelimited = absl::Span<const char>;
47
48 // Fixed-length 32-bit integer encoding:
49 // https://protobuf.dev/programming-guides/encoding/#non-varints
50 using I32 = absl::variant<uint32_t, int32_t, float>;
51
52 // Valid record type:
53 // https://protobuf.dev/programming-guides/encoding/#structure
54 using Value = absl::variant<Varint, I64, LengthDelimited, I32>;
55
56 // Field number for the protobuf value.
57 uint64_t field_number;
58
59 // Value to encode.
60 Value value;
61 };
62
63 // Estimates the number of bytes needed to encode `field` using
64 // protobuf encoding.
65 //
66 // The returned value might be larger than the actual number of bytes needed.
BufferSizeForStructuredProtoField(StructuredProtoField field)67 inline size_t BufferSizeForStructuredProtoField(StructuredProtoField field) {
68 // Visitor to estimate the number of bytes of one of the types contained
69 // inside `StructuredProtoField`.
70 struct BufferSizeVisitor final {
71 size_t operator()(StructuredProtoField::Varint /*unused*/) {
72 return BufferSizeFor(field_number, WireType::kVarint);
73 }
74
75 size_t operator()(StructuredProtoField::I64 /*unused*/) {
76 return BufferSizeFor(field_number, WireType::k64Bit);
77 }
78
79 size_t operator()(StructuredProtoField::LengthDelimited length_delimited) {
80 return BufferSizeFor(field_number, WireType::kLengthDelimited) +
81 length_delimited.size();
82 }
83
84 size_t operator()(StructuredProtoField::I32 /*unused*/) {
85 return BufferSizeFor(field_number, WireType::k32Bit);
86 }
87
88 uint64_t field_number;
89 };
90
91 return absl::visit(BufferSizeVisitor{field.field_number}, field.value);
92 }
93
94 // Encodes `field` into `buf` using protobuf encoding.
95 //
96 // On success, returns `true` and advances `buf` to the end of
97 // the bytes consumed.
98 //
99 // On failure (if `buf` was too small), returns `false`.
100 bool EncodeStructuredProtoField(StructuredProtoField field,
101 absl::Span<char>& buf);
102
103 } // namespace log_internal
104 ABSL_NAMESPACE_END
105 } // namespace absl
106
107 #endif // ABSL_LOG_INTERNAL_STRUCTURED_PROTO_H_
108