Action Engine
Loading...
Searching...
No Matches
misc.h
1// Copyright 2025 Google LLC
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// http://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#ifndef ACTIONENGINE_MSGPACK_MISC_H
16#define ACTIONENGINE_MSGPACK_MISC_H
17
18namespace act::msgpack {
19
20struct Timestamp {
21 int64_t seconds = 0;
22 uint64_t nanos = 0;
23
24 [[nodiscard]] absl::Time ToAbslTime() const {
25 return absl::FromUnixSeconds(seconds) + absl::Nanoseconds(nanos);
26 }
27
28 template <typename Clock>
29 [[nodiscard]] std::chrono::time_point<Clock> ToChronoTimePoint() const {
30 return std::chrono::time_point<Clock, std::chrono::nanoseconds>(
31 std::chrono::seconds(seconds) + std::chrono::nanoseconds(nanos));
32 }
33};
34
35inline absl::StatusOr<uint32_t> EgltMsgpackGetExtent(const LookupPointer& data,
36 Timestamp* absl_nullable) {
37 const auto [pos, end, _] = data;
38 if (*pos == FormatSignature::kFixExt4) {
39 if (end - pos < 6) {
40 return GetInsufficientDataError(data, "Timestamp");
41 }
42 return 6; // 2 bytes for the (ext) signature + 4 bytes for the value.
43 }
44 if (*pos == FormatSignature::kFixExt8) {
45 if (end - pos < 10) {
46 return GetInsufficientDataError(data, "Timestamp");
47 }
48 return 10; // 2 bytes for the (ext) signature + 8 bytes for the value.
49 }
50 if (*pos == FormatSignature::kExt8) {
51 if (end - pos < 15) {
52 return GetInsufficientDataError(data, "Timestamp");
53 }
54 return 15; // 3 bytes for the (ext) signature + 4 bytes for nanos,
55 // 8 bytes for seconds.
56 }
57 return GetInvalidFormatSignatureError(pos, "Timestamp", data.begin);
58}
59
60inline absl::Status EgltMsgpackSerialize(const Timestamp& value,
61 const InsertInfo& insert) {
62 // Check if the timestamp can be represented as a 32-bit timestamp.
63 if (value.seconds >= 0 && value.seconds <= 0xFFFFFFFF && value.nanos == 0) {
64 // This is timestamp 32
65 SerializedBytesVector result = ToBigEndianBytes<uint32_t>(value.seconds,
66 /*pad=*/2);
67 result[0] = FormatSignature::kFixExt4;
68 result[1] = 255; // Ext type for Timestamp
69 insert.bytes->insert(insert.at, result.begin(), result.end());
70 return absl::OkStatus();
71 }
72 // TODO: timestamp 64
73 // timestamp 96
74 if (insert.at == insert.bytes->end()) {
75 insert.bytes->reserve(insert.bytes->size() + 15);
76 }
77
78 insert.bytes->insert(insert.at, {FormatSignature::kExt8, 12, 255});
79 auto nanos_bytes =
80 ToBigEndianBytes(static_cast<uint32_t>(value.nanos), /*pad=*/0);
81 auto seconds_bytes = ToBigEndianBytes(value.seconds, /*pad=*/0);
82 insert.bytes->insert(insert.at, nanos_bytes.begin(), nanos_bytes.end());
83 insert.bytes->insert(insert.at, seconds_bytes.begin(), seconds_bytes.end());
84 return absl::OkStatus();
85}
86
87inline absl::StatusOr<uint32_t> EgltMsgpackDeserialize(
88 const LookupPointer& data, Timestamp* absl_nonnull output) {
89 const auto [pos, end, _] = data;
90 if (*pos == FormatSignature::kFixExt4) {
91 if (end - pos < 6) {
92 return GetInsufficientDataError(data, "Timestamp");
93 }
94 output->seconds = FromBigEndianBytes<uint32_t>(pos + 2);
95 output->nanos = 0;
96 return 6; // 2 bytes for the (ext) signature + 4 bytes for the value.
97 }
98 if (*pos == FormatSignature::kFixExt8) {
99 return absl::UnimplementedError(
100 "FixExt8 for Timestamp64 is not yet implemented.");
101 }
102 if (*pos == FormatSignature::kExt8) {
103 if (end - pos < 15) {
104 return GetInsufficientDataError(data, "Timestamp");
105 }
106 output->nanos = FromBigEndianBytes<uint32_t>(pos + 3);
107 output->seconds = FromBigEndianBytes<int64_t>(pos + 7);
108 return 15; // 3 bytes for the (ext) signature + 4 bytes for nanos,
109 // 8 bytes for seconds.
110 }
111 return GetInvalidFormatSignatureError(pos, "Timestamp", data.begin);
112}
113
114inline absl::StatusOr<uint32_t> EgltMsgpackGetExtent(
115 const LookupPointer& data, absl::Time* absl_nullable) {
116 return EgltMsgpackGetExtent(data, static_cast<Timestamp*>(nullptr));
117}
118
119inline absl::Status EgltMsgpackSerialize(absl::Time value,
120 const InsertInfo& insert) {
121 const uint64_t nanos = absl::ToUnixNanos(value) % 1000000000;
122 return EgltMsgpackSerialize(Timestamp{absl::ToUnixSeconds(value), nanos},
123 insert);
124}
125
126inline absl::StatusOr<uint32_t> EgltMsgpackDeserialize(
127 const LookupPointer& data, absl::Time* absl_nonnull output) {
128 Timestamp timestamp;
129 auto status = EgltMsgpackDeserialize(data, &timestamp);
130 if (!status.ok()) {
131 return status;
132 }
133 *output = timestamp.ToAbslTime();
134 return status;
135}
136
137inline absl::StatusOr<uint32_t> EgltMsgpackGetExtent(const LookupPointer& data,
138 bool* absl_nullable) {
139 const auto [pos, end, _] = data;
140 if (pos >= end) {
141 return absl::InvalidArgumentError(
142 "Position is not within the bounds of the data.");
143 }
144 if (*pos == FormatSignature::kFalse || *pos == FormatSignature::kTrue) {
145 return 1;
146 }
147 return absl::InvalidArgumentError(
148 "Expected a boolean value, but found a different format signature.");
149}
150
151inline absl::Status EgltMsgpackSerialize(bool value, const InsertInfo& insert) {
152 if (value) {
153 insert.bytes->insert(insert.at, FormatSignature::kTrue);
154 return absl::OkStatus();
155 }
156 insert.bytes->insert(insert.at, FormatSignature::kFalse);
157 return absl::OkStatus();
158}
159
160inline absl::StatusOr<uint32_t> EgltMsgpackDeserialize(
161 const LookupPointer& data, bool* absl_nonnull output) {
162 const auto [pos, end, _] = data;
163 if (*pos == FormatSignature::kFalse) {
164 *output = false;
165 return absl::OkStatus();
166 }
167 if (*pos == FormatSignature::kTrue) {
168 *output = true;
169 return absl::OkStatus();
170 }
171 return GetInvalidFormatSignatureError(pos, "bool", data.begin);
172}
173
174template <typename T>
175absl::StatusOr<uint32_t> EgltMsgpackGetExtent(const LookupPointer& data,
176 std::optional<T>* absl_nullable) {
177 const auto [pos, end, _] = data;
178 if (*pos == FormatSignature::kNil) {
179 return 1;
180 }
181 return GetExtent<T>(pos, end);
182}
183
184template <typename T>
185absl::Status EgltMsgpackSerialize(const std::optional<T>& value,
186 const InsertInfo& insert) {
187 if (!value) {
188 insert.bytes->insert(insert.at, FormatSignature::kNil);
189 return absl::OkStatus();
190 }
191 return Serialize<T>(*value, insert);
192}
193
194template <typename T>
195absl::StatusOr<uint32_t> EgltMsgpackDeserialize(
196 const LookupPointer& data, std::optional<T>* absl_nonnull output) {
197 const auto [pos, end, _] = data;
198 if (*pos == FormatSignature::kNil) {
199 *output = std::nullopt;
200 }
201 *output = Deserialize<T>(pos, end);
202 return absl::OkStatus();
203}
204
205inline absl::StatusOr<uint32_t> EgltMsgpackGetExtent(
206 const LookupPointer& data, std::nullopt_t* absl_nullable) {
207 if (data.pos >= data.end) {
208 return absl::InvalidArgumentError(
209 "Position is not within the bounds of the data.");
210 }
211 if (*data.pos == FormatSignature::kNil) {
212 return 1; // 1 byte for the nil signature.
213 }
214 return GetInvalidFormatSignatureError(data.pos, "std::nullopt_t", data.begin);
215}
216
217inline absl::Status EgltMsgpackSerialize(std::nullopt_t,
218 const InsertInfo& insert) {
219 insert.bytes->insert(insert.at, FormatSignature::kNil);
220 return absl::OkStatus();
221}
222
223inline absl::StatusOr<uint32_t> EgltMsgpackDeserialize(
224 const LookupPointer& data, std::nullopt_t* absl_nonnull output) {
225 const auto [pos, end, _] = data;
226 if (*pos == FormatSignature::kNil) {
227 *output = std::nullopt;
228 return 1; // 1 byte for the nil signature.
229 }
230 return GetInvalidFormatSignatureError(pos, "std::nullopt_t", data.begin);
231}
232
233} // namespace act::msgpack
234
235#endif // ACTIONENGINE_MSGPACK_MISC_H