/proc/self/cwd/runtime/standard/time_functions.cc
Line | Count | Source |
1 | | // Copyright 2023 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 | | // 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 | | #include "runtime/standard/time_functions.h" |
16 | | |
17 | | #include <cstdint> |
18 | | #include <functional> |
19 | | #include <string> |
20 | | |
21 | | #include "absl/status/status.h" |
22 | | #include "absl/status/statusor.h" |
23 | | #include "absl/strings/match.h" |
24 | | #include "absl/strings/str_replace.h" |
25 | | #include "absl/strings/string_view.h" |
26 | | #include "absl/time/civil_time.h" |
27 | | #include "absl/time/time.h" |
28 | | #include "base/builtins.h" |
29 | | #include "base/function_adapter.h" |
30 | | #include "common/value.h" |
31 | | #include "internal/overflow.h" |
32 | | #include "internal/status_macros.h" |
33 | | #include "runtime/function.h" |
34 | | #include "runtime/function_registry.h" |
35 | | #include "runtime/runtime_options.h" |
36 | | #include "google/protobuf/arena.h" |
37 | | |
38 | | namespace cel { |
39 | | namespace { |
40 | | |
41 | | // Timestamp |
42 | | absl::Status FindTimeBreakdown(absl::Time timestamp, absl::string_view tz, |
43 | 0 | absl::TimeZone::CivilInfo* breakdown) { |
44 | 0 | absl::TimeZone time_zone; |
45 | | |
46 | | // Early return if there is no timezone. |
47 | 0 | if (tz.empty()) { |
48 | 0 | *breakdown = time_zone.At(timestamp); |
49 | 0 | return absl::OkStatus(); |
50 | 0 | } |
51 | | |
52 | | // Check to see whether the timezone is an IANA timezone. |
53 | 0 | if (absl::LoadTimeZone(tz, &time_zone)) { |
54 | 0 | *breakdown = time_zone.At(timestamp); |
55 | 0 | return absl::OkStatus(); |
56 | 0 | } |
57 | | |
58 | | // Check for times of the format: [+-]HH:MM and convert them into durations |
59 | | // specified as [+-]HHhMMm. |
60 | 0 | if (absl::StrContains(tz, ":")) { |
61 | 0 | std::string dur = absl::StrCat(tz, "m"); |
62 | 0 | absl::StrReplaceAll({{":", "h"}}, &dur); |
63 | 0 | absl::Duration d; |
64 | 0 | if (absl::ParseDuration(dur, &d)) { |
65 | 0 | timestamp += d; |
66 | 0 | *breakdown = time_zone.At(timestamp); |
67 | 0 | return absl::OkStatus(); |
68 | 0 | } |
69 | 0 | } |
70 | | |
71 | | // Otherwise, error. |
72 | 0 | return absl::InvalidArgumentError("Invalid timezone"); |
73 | 0 | } |
74 | | |
75 | | Value GetTimeBreakdownPart( |
76 | | absl::Time timestamp, absl::string_view tz, |
77 | | const std::function<int64_t(const absl::TimeZone::CivilInfo&)>& |
78 | | extractor_func, |
79 | 0 | google::protobuf::Arena* arena) { |
80 | 0 | absl::TimeZone::CivilInfo breakdown; |
81 | 0 | auto status = FindTimeBreakdown(timestamp, tz, &breakdown); |
82 | |
|
83 | 0 | if (!status.ok()) { |
84 | 0 | return ErrorValue::From(status, arena); |
85 | 0 | } |
86 | | |
87 | 0 | return IntValue(extractor_func(breakdown)); |
88 | 0 | } |
89 | | |
90 | | Value GetFullYear(absl::Time timestamp, absl::string_view tz, |
91 | 0 | const Function::InvokeContext& context) { |
92 | 0 | return GetTimeBreakdownPart( |
93 | 0 | timestamp, tz, |
94 | 0 | [](const absl::TimeZone::CivilInfo& breakdown) { |
95 | 0 | return breakdown.cs.year(); |
96 | 0 | }, |
97 | 0 | context.arena()); |
98 | 0 | } |
99 | | |
100 | | Value GetMonth(absl::Time timestamp, absl::string_view tz, |
101 | 0 | const Function::InvokeContext& context) { |
102 | 0 | return GetTimeBreakdownPart( |
103 | 0 | timestamp, tz, |
104 | 0 | [](const absl::TimeZone::CivilInfo& breakdown) { |
105 | 0 | return breakdown.cs.month() - 1; |
106 | 0 | }, |
107 | 0 | context.arena()); |
108 | 0 | } |
109 | | |
110 | | Value GetDayOfYear(absl::Time timestamp, absl::string_view tz, |
111 | 0 | const Function::InvokeContext& context) { |
112 | 0 | return GetTimeBreakdownPart( |
113 | 0 | timestamp, tz, |
114 | 0 | [](const absl::TimeZone::CivilInfo& breakdown) { |
115 | 0 | return absl::GetYearDay(absl::CivilDay(breakdown.cs)) - 1; |
116 | 0 | }, |
117 | 0 | context.arena()); |
118 | 0 | } |
119 | | |
120 | | Value GetDayOfMonth(absl::Time timestamp, absl::string_view tz, |
121 | 0 | const Function::InvokeContext& context) { |
122 | 0 | return GetTimeBreakdownPart( |
123 | 0 | timestamp, tz, |
124 | 0 | [](const absl::TimeZone::CivilInfo& breakdown) { |
125 | 0 | return breakdown.cs.day() - 1; |
126 | 0 | }, |
127 | 0 | context.arena()); |
128 | 0 | } |
129 | | |
130 | | Value GetDate(absl::Time timestamp, absl::string_view tz, |
131 | 0 | const Function::InvokeContext& context) { |
132 | 0 | return GetTimeBreakdownPart( |
133 | 0 | timestamp, tz, |
134 | 0 | [](const absl::TimeZone::CivilInfo& breakdown) { |
135 | 0 | return breakdown.cs.day(); |
136 | 0 | }, |
137 | 0 | context.arena()); |
138 | 0 | } |
139 | | |
140 | | Value GetDayOfWeek(absl::Time timestamp, absl::string_view tz, |
141 | 0 | const Function::InvokeContext& context) { |
142 | 0 | return GetTimeBreakdownPart( |
143 | 0 | timestamp, tz, |
144 | 0 | [](const absl::TimeZone::CivilInfo& breakdown) { |
145 | 0 | absl::Weekday weekday = absl::GetWeekday(breakdown.cs); |
146 | | |
147 | | // get day of week from the date in UTC, zero-based, zero for Sunday, |
148 | | // based on GetDayOfWeek CEL function definition. |
149 | 0 | int weekday_num = static_cast<int>(weekday); |
150 | 0 | weekday_num = (weekday_num == 6) ? 0 : weekday_num + 1; |
151 | 0 | return weekday_num; |
152 | 0 | }, |
153 | 0 | context.arena()); |
154 | 0 | } |
155 | | |
156 | | Value GetHours(absl::Time timestamp, absl::string_view tz, |
157 | 0 | const Function::InvokeContext& context) { |
158 | 0 | return GetTimeBreakdownPart( |
159 | 0 | timestamp, tz, |
160 | 0 | [](const absl::TimeZone::CivilInfo& breakdown) { |
161 | 0 | return breakdown.cs.hour(); |
162 | 0 | }, |
163 | 0 | context.arena()); |
164 | 0 | } |
165 | | |
166 | | Value GetMinutes(absl::Time timestamp, absl::string_view tz, |
167 | 0 | const Function::InvokeContext& context) { |
168 | 0 | return GetTimeBreakdownPart( |
169 | 0 | timestamp, tz, |
170 | 0 | [](const absl::TimeZone::CivilInfo& breakdown) { |
171 | 0 | return breakdown.cs.minute(); |
172 | 0 | }, |
173 | 0 | context.arena()); |
174 | 0 | } |
175 | | |
176 | | Value GetSeconds(absl::Time timestamp, absl::string_view tz, |
177 | 0 | const Function::InvokeContext& context) { |
178 | 0 | return GetTimeBreakdownPart( |
179 | 0 | timestamp, tz, |
180 | 0 | [](const absl::TimeZone::CivilInfo& breakdown) { |
181 | 0 | return breakdown.cs.second(); |
182 | 0 | }, |
183 | 0 | context.arena()); |
184 | 0 | } |
185 | | |
186 | | Value GetMilliseconds(absl::Time timestamp, absl::string_view tz, |
187 | 0 | const Function::InvokeContext& context) { |
188 | 0 | return GetTimeBreakdownPart( |
189 | 0 | timestamp, tz, |
190 | 0 | [](const absl::TimeZone::CivilInfo& breakdown) { |
191 | 0 | return absl::ToInt64Milliseconds(breakdown.subsecond); |
192 | 0 | }, |
193 | 0 | context.arena()); |
194 | 0 | } |
195 | | |
196 | | absl::Status RegisterTimestampFunctions(FunctionRegistry& registry, |
197 | 22.7k | const RuntimeOptions& options) { |
198 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
199 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
200 | 22.7k | CreateDescriptor(builtin::kFullYear, true), |
201 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
202 | 22.7k | WrapFunction([](absl::Time ts, const StringValue& tz, |
203 | 22.7k | const Function::InvokeContext& context) -> Value { |
204 | 22.7k | return GetFullYear(ts, tz.ToString(), context); |
205 | 22.7k | }))); |
206 | | |
207 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
208 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor( |
209 | 22.7k | builtin::kFullYear, true), |
210 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::WrapFunction( |
211 | 22.7k | [](absl::Time ts, const Function::InvokeContext& context) -> Value { |
212 | 22.7k | return GetFullYear(ts, "", context); |
213 | 22.7k | }))); |
214 | | |
215 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
216 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
217 | 22.7k | CreateDescriptor(builtin::kMonth, true), |
218 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
219 | 22.7k | WrapFunction([](absl::Time ts, const StringValue& tz, |
220 | 22.7k | const Function::InvokeContext& context) -> Value { |
221 | 22.7k | return GetMonth(ts, tz.ToString(), context); |
222 | 22.7k | }))); |
223 | | |
224 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
225 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(builtin::kMonth, |
226 | 22.7k | true), |
227 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::WrapFunction( |
228 | 22.7k | [](absl::Time ts, const Function::InvokeContext& context) -> Value { |
229 | 22.7k | return GetMonth(ts, "", context); |
230 | 22.7k | }))); |
231 | | |
232 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
233 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
234 | 22.7k | CreateDescriptor(builtin::kDayOfYear, true), |
235 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
236 | 22.7k | WrapFunction([](absl::Time ts, const StringValue& tz, |
237 | 22.7k | const Function::InvokeContext& context) -> Value { |
238 | 22.7k | return GetDayOfYear(ts, tz.ToString(), context); |
239 | 22.7k | }))); |
240 | | |
241 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
242 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor( |
243 | 22.7k | builtin::kDayOfYear, true), |
244 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::WrapFunction( |
245 | 22.7k | [](absl::Time ts, const Function::InvokeContext& context) -> Value { |
246 | 22.7k | return GetDayOfYear(ts, "", context); |
247 | 22.7k | }))); |
248 | | |
249 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
250 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
251 | 22.7k | CreateDescriptor(builtin::kDayOfMonth, true), |
252 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
253 | 22.7k | WrapFunction([](absl::Time ts, const StringValue& tz, |
254 | 22.7k | const Function::InvokeContext& context) -> Value { |
255 | 22.7k | return GetDayOfMonth(ts, tz.ToString(), context); |
256 | 22.7k | }))); |
257 | | |
258 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
259 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor( |
260 | 22.7k | builtin::kDayOfMonth, true), |
261 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::WrapFunction( |
262 | 22.7k | [](absl::Time ts, const Function::InvokeContext& context) -> Value { |
263 | 22.7k | return GetDayOfMonth(ts, "", context); |
264 | 22.7k | }))); |
265 | | |
266 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
267 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
268 | 22.7k | CreateDescriptor(builtin::kDate, true), |
269 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
270 | 22.7k | WrapFunction([](absl::Time ts, const StringValue& tz, |
271 | 22.7k | const Function::InvokeContext& context) -> Value { |
272 | 22.7k | return GetDate(ts, tz.ToString(), context); |
273 | 22.7k | }))); |
274 | | |
275 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
276 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(builtin::kDate, |
277 | 22.7k | true), |
278 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::WrapFunction( |
279 | 22.7k | [](absl::Time ts, const Function::InvokeContext& context) -> Value { |
280 | 22.7k | return GetDate(ts, "", context); |
281 | 22.7k | }))); |
282 | | |
283 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
284 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
285 | 22.7k | CreateDescriptor(builtin::kDayOfWeek, true), |
286 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
287 | 22.7k | WrapFunction([](absl::Time ts, const StringValue& tz, |
288 | 22.7k | const Function::InvokeContext& context) -> Value { |
289 | 22.7k | return GetDayOfWeek(ts, tz.ToString(), context); |
290 | 22.7k | }))); |
291 | | |
292 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
293 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor( |
294 | 22.7k | builtin::kDayOfWeek, true), |
295 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::WrapFunction( |
296 | 22.7k | [](absl::Time ts, const Function::InvokeContext& context) -> Value { |
297 | 22.7k | return GetDayOfWeek(ts, "", context); |
298 | 22.7k | }))); |
299 | | |
300 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
301 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
302 | 22.7k | CreateDescriptor(builtin::kHours, true), |
303 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
304 | 22.7k | WrapFunction([](absl::Time ts, const StringValue& tz, |
305 | 22.7k | const Function::InvokeContext& context) -> Value { |
306 | 22.7k | return GetHours(ts, tz.ToString(), context); |
307 | 22.7k | }))); |
308 | | |
309 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
310 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor(builtin::kHours, |
311 | 22.7k | true), |
312 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::WrapFunction( |
313 | 22.7k | [](absl::Time ts, const Function::InvokeContext& context) -> Value { |
314 | 22.7k | return GetHours(ts, "", context); |
315 | 22.7k | }))); |
316 | | |
317 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
318 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
319 | 22.7k | CreateDescriptor(builtin::kMinutes, true), |
320 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
321 | 22.7k | WrapFunction([](absl::Time ts, const StringValue& tz, |
322 | 22.7k | const Function::InvokeContext& context) -> Value { |
323 | 22.7k | return GetMinutes(ts, tz.ToString(), context); |
324 | 22.7k | }))); |
325 | | |
326 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
327 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor( |
328 | 22.7k | builtin::kMinutes, true), |
329 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::WrapFunction( |
330 | 22.7k | [](absl::Time ts, const Function::InvokeContext& context) -> Value { |
331 | 22.7k | return GetMinutes(ts, "", context); |
332 | 22.7k | }))); |
333 | | |
334 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
335 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
336 | 22.7k | CreateDescriptor(builtin::kSeconds, true), |
337 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
338 | 22.7k | WrapFunction([](absl::Time ts, const StringValue& tz, |
339 | 22.7k | const Function::InvokeContext& context) -> Value { |
340 | 22.7k | return GetSeconds(ts, tz.ToString(), context); |
341 | 22.7k | }))); |
342 | | |
343 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
344 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor( |
345 | 22.7k | builtin::kSeconds, true), |
346 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::WrapFunction( |
347 | 22.7k | [](absl::Time ts, const Function::InvokeContext& context) -> Value { |
348 | 22.7k | return GetSeconds(ts, "", context); |
349 | 22.7k | }))); |
350 | | |
351 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
352 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
353 | 22.7k | CreateDescriptor(builtin::kMilliseconds, true), |
354 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, const StringValue&>:: |
355 | 22.7k | WrapFunction([](absl::Time ts, const StringValue& tz, |
356 | 22.7k | const Function::InvokeContext& context) -> Value { |
357 | 22.7k | return GetMilliseconds(ts, tz.ToString(), context); |
358 | 22.7k | }))); |
359 | | |
360 | 22.7k | return registry.Register( |
361 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::CreateDescriptor( |
362 | 22.7k | builtin::kMilliseconds, true), |
363 | 22.7k | UnaryFunctionAdapter<Value, absl::Time>::WrapFunction( |
364 | 22.7k | [](absl::Time ts, const Function::InvokeContext& context) -> Value { |
365 | 0 | return GetMilliseconds(ts, "", context); |
366 | 0 | })); |
367 | 22.7k | } |
368 | | |
369 | | absl::Status RegisterCheckedTimeArithmeticFunctions( |
370 | 0 | FunctionRegistry& registry) { |
371 | 0 | CEL_RETURN_IF_ERROR(registry.Register( |
372 | 0 | BinaryFunctionAdapter<Value, absl::Time, |
373 | 0 | absl::Duration>::CreateDescriptor(builtin::kAdd, |
374 | 0 | false), |
375 | 0 | BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time, absl::Duration>:: |
376 | 0 | WrapFunction([](absl::Time t1, absl::Duration d2, |
377 | 0 | const Function::InvokeContext& context) |
378 | 0 | -> absl::StatusOr<Value> { |
379 | 0 | auto sum = cel::internal::CheckedAdd(t1, d2); |
380 | 0 | if (!sum.ok()) { |
381 | 0 | return ErrorValue::From(sum.status(), context.arena()); |
382 | 0 | } |
383 | 0 | return TimestampValue(*sum); |
384 | 0 | }))); |
385 | | |
386 | 0 | CEL_RETURN_IF_ERROR(registry.Register( |
387 | 0 | BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Duration, |
388 | 0 | absl::Time>::CreateDescriptor(builtin::kAdd, false), |
389 | 0 | BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Duration, absl::Time>:: |
390 | 0 | WrapFunction([](absl::Duration d2, absl::Time t1, |
391 | 0 | const Function::InvokeContext& context) |
392 | 0 | -> absl::StatusOr<Value> { |
393 | 0 | auto sum = cel::internal::CheckedAdd(t1, d2); |
394 | 0 | if (!sum.ok()) { |
395 | 0 | return ErrorValue::From(sum.status(), context.arena()); |
396 | 0 | } |
397 | 0 | return TimestampValue(*sum); |
398 | 0 | }))); |
399 | | |
400 | 0 | CEL_RETURN_IF_ERROR(registry.Register( |
401 | 0 | BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Duration, |
402 | 0 | absl::Duration>::CreateDescriptor(builtin::kAdd, |
403 | 0 | false), |
404 | 0 | BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Duration, |
405 | 0 | absl::Duration>:: |
406 | 0 | WrapFunction([](absl::Duration d1, absl::Duration d2, |
407 | 0 | const Function::InvokeContext& context) |
408 | 0 | -> absl::StatusOr<Value> { |
409 | 0 | auto sum = cel::internal::CheckedAdd(d1, d2); |
410 | 0 | if (!sum.ok()) { |
411 | 0 | return ErrorValue::From(sum.status(), context.arena()); |
412 | 0 | } |
413 | 0 | return DurationValue(*sum); |
414 | 0 | }))); |
415 | | |
416 | 0 | CEL_RETURN_IF_ERROR(registry.Register( |
417 | 0 | BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time, absl::Duration>:: |
418 | 0 | CreateDescriptor(builtin::kSubtract, false), |
419 | 0 | BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time, absl::Duration>:: |
420 | 0 | WrapFunction([](absl::Time t1, absl::Duration d2, |
421 | 0 | const Function::InvokeContext& context) |
422 | 0 | -> absl::StatusOr<Value> { |
423 | 0 | auto diff = cel::internal::CheckedSub(t1, d2); |
424 | 0 | if (!diff.ok()) { |
425 | 0 | return ErrorValue::From(diff.status(), context.arena()); |
426 | 0 | } |
427 | 0 | return TimestampValue(*diff); |
428 | 0 | }))); |
429 | | |
430 | 0 | CEL_RETURN_IF_ERROR(registry.Register( |
431 | 0 | BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time, |
432 | 0 | absl::Time>::CreateDescriptor(builtin::kSubtract, |
433 | 0 | false), |
434 | 0 | BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Time, absl::Time>:: |
435 | 0 | WrapFunction([](absl::Time t1, absl::Time t2, |
436 | 0 | const Function::InvokeContext& context) |
437 | 0 | -> absl::StatusOr<Value> { |
438 | 0 | auto diff = cel::internal::CheckedSub(t1, t2); |
439 | 0 | if (!diff.ok()) { |
440 | 0 | return ErrorValue::From(diff.status(), context.arena()); |
441 | 0 | } |
442 | 0 | return DurationValue(*diff); |
443 | 0 | }))); |
444 | | |
445 | 0 | CEL_RETURN_IF_ERROR(registry.Register( |
446 | 0 | BinaryFunctionAdapter< |
447 | 0 | absl::StatusOr<Value>, absl::Duration, |
448 | 0 | absl::Duration>::CreateDescriptor(builtin::kSubtract, false), |
449 | 0 | BinaryFunctionAdapter<absl::StatusOr<Value>, absl::Duration, |
450 | 0 | absl::Duration>:: |
451 | 0 | WrapFunction([](absl::Duration d1, absl::Duration d2, |
452 | 0 | const Function::InvokeContext& context) |
453 | 0 | -> absl::StatusOr<Value> { |
454 | 0 | auto diff = cel::internal::CheckedSub(d1, d2); |
455 | 0 | if (!diff.ok()) { |
456 | 0 | return ErrorValue::From(diff.status(), context.arena()); |
457 | 0 | } |
458 | 0 | return DurationValue(*diff); |
459 | 0 | }))); |
460 | | |
461 | 0 | return absl::OkStatus(); |
462 | 0 | } |
463 | | |
464 | | absl::Status RegisterUncheckedTimeArithmeticFunctions( |
465 | 22.7k | FunctionRegistry& registry) { |
466 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
467 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, |
468 | 22.7k | absl::Duration>::CreateDescriptor(builtin::kAdd, |
469 | 22.7k | false), |
470 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, absl::Duration>::WrapFunction( |
471 | 22.7k | [](absl::Time t1, absl::Duration d2) -> Value { |
472 | 22.7k | return UnsafeTimestampValue(t1 + d2); |
473 | 22.7k | }))); |
474 | | |
475 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
476 | 22.7k | BinaryFunctionAdapter<Value, absl::Duration, |
477 | 22.7k | absl::Time>::CreateDescriptor(builtin::kAdd, false), |
478 | 22.7k | BinaryFunctionAdapter<Value, absl::Duration, absl::Time>::WrapFunction( |
479 | 22.7k | [](absl::Duration d2, absl::Time t1) -> Value { |
480 | 22.7k | return UnsafeTimestampValue(t1 + d2); |
481 | 22.7k | }))); |
482 | | |
483 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
484 | 22.7k | BinaryFunctionAdapter<Value, absl::Duration, |
485 | 22.7k | absl::Duration>::CreateDescriptor(builtin::kAdd, |
486 | 22.7k | false), |
487 | 22.7k | BinaryFunctionAdapter<Value, absl::Duration, absl::Duration>:: |
488 | 22.7k | WrapFunction([](absl::Duration d1, absl::Duration d2) -> Value { |
489 | 22.7k | return UnsafeDurationValue(d1 + d2); |
490 | 22.7k | }))); |
491 | | |
492 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
493 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, absl::Duration>:: |
494 | 22.7k | CreateDescriptor(builtin::kSubtract, false), |
495 | | |
496 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, absl::Duration>::WrapFunction( |
497 | | |
498 | 22.7k | [](absl::Time t1, absl::Duration d2) -> Value { |
499 | 22.7k | return UnsafeTimestampValue(t1 - d2); |
500 | 22.7k | }))); |
501 | | |
502 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
503 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, absl::Time>::CreateDescriptor( |
504 | 22.7k | builtin::kSubtract, false), |
505 | 22.7k | BinaryFunctionAdapter<Value, absl::Time, absl::Time>::WrapFunction( |
506 | | |
507 | 22.7k | [](absl::Time t1, absl::Time t2) -> Value { |
508 | 22.7k | return UnsafeDurationValue(t1 - t2); |
509 | 22.7k | }))); |
510 | | |
511 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
512 | 22.7k | BinaryFunctionAdapter<Value, absl::Duration, absl::Duration>:: |
513 | 22.7k | CreateDescriptor(builtin::kSubtract, false), |
514 | 22.7k | BinaryFunctionAdapter<Value, absl::Duration, absl::Duration>:: |
515 | 22.7k | WrapFunction([](absl::Duration d1, absl::Duration d2) -> Value { |
516 | 22.7k | return UnsafeDurationValue(d1 - d2); |
517 | 22.7k | }))); |
518 | | |
519 | 22.7k | return absl::OkStatus(); |
520 | 22.7k | } |
521 | | |
522 | 22.7k | absl::Status RegisterDurationFunctions(FunctionRegistry& registry) { |
523 | | // duration breakdown accessor functions |
524 | 22.7k | using DurationAccessorFunction = |
525 | 22.7k | UnaryFunctionAdapter<int64_t, absl::Duration>; |
526 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
527 | 22.7k | DurationAccessorFunction::CreateDescriptor(builtin::kHours, true), |
528 | 22.7k | DurationAccessorFunction::WrapFunction( |
529 | 22.7k | [](absl::Duration d) -> int64_t { return absl::ToInt64Hours(d); }))); |
530 | | |
531 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
532 | 22.7k | DurationAccessorFunction::CreateDescriptor(builtin::kMinutes, true), |
533 | 22.7k | DurationAccessorFunction::WrapFunction([](absl::Duration d) -> int64_t { |
534 | 22.7k | return absl::ToInt64Minutes(d); |
535 | 22.7k | }))); |
536 | | |
537 | 22.7k | CEL_RETURN_IF_ERROR(registry.Register( |
538 | 22.7k | DurationAccessorFunction::CreateDescriptor(builtin::kSeconds, true), |
539 | 22.7k | DurationAccessorFunction::WrapFunction([](absl::Duration d) -> int64_t { |
540 | 22.7k | return absl::ToInt64Seconds(d); |
541 | 22.7k | }))); |
542 | | |
543 | 22.7k | return registry.Register( |
544 | 22.7k | DurationAccessorFunction::CreateDescriptor(builtin::kMilliseconds, true), |
545 | 22.7k | DurationAccessorFunction::WrapFunction([](absl::Duration d) -> int64_t { |
546 | 0 | constexpr int64_t millis_per_second = 1000L; |
547 | 0 | return absl::ToInt64Milliseconds(d) % millis_per_second; |
548 | 0 | })); |
549 | 22.7k | } |
550 | | |
551 | | } // namespace |
552 | | |
553 | | absl::Status RegisterTimeFunctions(FunctionRegistry& registry, |
554 | 22.7k | const RuntimeOptions& options) { |
555 | 22.7k | CEL_RETURN_IF_ERROR(RegisterTimestampFunctions(registry, options)); |
556 | 22.7k | CEL_RETURN_IF_ERROR(RegisterDurationFunctions(registry)); |
557 | | |
558 | | // Special arithmetic operators for Timestamp and Duration |
559 | | // TODO(uncreated-issue/37): deprecate unchecked time math functions when clients no |
560 | | // longer depend on them. |
561 | 22.7k | if (options.enable_timestamp_duration_overflow_errors) { |
562 | 0 | return RegisterCheckedTimeArithmeticFunctions(registry); |
563 | 0 | } |
564 | | |
565 | 22.7k | return RegisterUncheckedTimeArithmeticFunctions(registry); |
566 | 22.7k | } |
567 | | |
568 | | } // namespace cel |