Skip to content

Commit ee1b4db

Browse files
seirlcopybara-github
authored andcommitted
Implement optional.unwrap() and .unwrapOpt() functions.
PiperOrigin-RevId: 721534371
1 parent 39fbda1 commit ee1b4db

3 files changed

Lines changed: 65 additions & 1 deletion

File tree

runtime/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,7 @@ cc_library(
546546
"//runtime/internal:runtime_impl",
547547
"@com_google_absl//absl/status",
548548
"@com_google_absl//absl/status:statusor",
549+
"@com_google_absl//absl/strings:str_format",
549550
"@com_google_absl//absl/strings:string_view",
550551
"@com_google_absl//absl/types:optional",
551552
],

runtime/optional_types.cc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323

2424
#include "absl/status/status.h"
2525
#include "absl/status/statusor.h"
26+
#include "absl/strings/str_format.h"
2627
#include "absl/strings/string_view.h"
2728
#include "absl/types/optional.h"
2829
#include "base/function_adapter.h"
@@ -211,6 +212,33 @@ absl::StatusOr<Value> OptionalOptIndexOptionalValue(
211212
return ErrorValue{runtime_internal::CreateNoMatchingOverloadError("_[?_]")};
212213
}
213214

215+
absl::StatusOr<Value> ListUnwrapOpt(ValueManager& value_manager,
216+
const ListValue& list) {
217+
CEL_ASSIGN_OR_RETURN(auto builder,
218+
value_manager.NewListValueBuilder(ListType()));
219+
CEL_ASSIGN_OR_RETURN(auto list_size, list.Size());
220+
builder->Reserve(list_size);
221+
222+
absl::Status status = list.ForEach(
223+
value_manager, [&](const Value& value) -> absl::StatusOr<bool> {
224+
if (auto optional_value = value.AsOptional(); optional_value) {
225+
if (optional_value->HasValue()) {
226+
CEL_RETURN_IF_ERROR(builder->Add(optional_value->Value()));
227+
}
228+
} else {
229+
return absl::InvalidArgumentError(absl::StrFormat(
230+
"optional.unwrap() expected a list(optional(T)), but %s "
231+
"was found in the list.",
232+
value.GetTypeName()));
233+
}
234+
return true;
235+
});
236+
if (!status.ok()) {
237+
return ErrorValue(status);
238+
}
239+
return std::move(*builder).Build();
240+
}
241+
214242
absl::Status RegisterOptionalTypeFunctions(FunctionRegistry& registry,
215243
const RuntimeOptions& options) {
216244
if (!options.enable_qualified_type_identifiers) {
@@ -274,6 +302,16 @@ absl::Status RegisterOptionalTypeFunctions(FunctionRegistry& registry,
274302
Value>::CreateDescriptor("_[?_]", false),
275303
BinaryFunctionAdapter<absl::StatusOr<Value>, OpaqueValue, Value>::
276304
WrapFunction(&OptionalOptIndexOptionalValue)));
305+
CEL_RETURN_IF_ERROR(registry.Register(
306+
UnaryFunctionAdapter<absl::StatusOr<Value>, ListValue>::CreateDescriptor(
307+
"optional.unwrap", false),
308+
UnaryFunctionAdapter<absl::StatusOr<Value>, ListValue>::WrapFunction(
309+
&ListUnwrapOpt)));
310+
CEL_RETURN_IF_ERROR(registry.Register(
311+
UnaryFunctionAdapter<absl::StatusOr<Value>, ListValue>::CreateDescriptor(
312+
"unwrapOpt", true),
313+
UnaryFunctionAdapter<absl::StatusOr<Value>, ListValue>::WrapFunction(
314+
&ListUnwrapOpt)));
277315
return absl::OkStatus();
278316
}
279317

runtime/optional_types_test.cc

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,32 @@ INSTANTIATE_TEST_SUITE_P(
271271
{"optional_orValue_present", "optional.of(1).orValue(2)",
272272
IntValueIs(1)},
273273
{"list_of_optional", "[optional.of(1)][0].orValue(1)",
274-
IntValueIs(1)}}),
274+
IntValueIs(1)},
275+
{"list_unwrap_empty", "optional.unwrap([]) == []",
276+
BoolValueIs(true)},
277+
{"list_unwrap_empty_optional_none",
278+
"optional.unwrap([optional.none(), optional.none()]) == []",
279+
BoolValueIs(true)},
280+
{"list_unwrap_three_elements",
281+
"optional.unwrap([optional.of(42), optional.none(), "
282+
"optional.of(\"a\")]) == [42, \"a\"]",
283+
BoolValueIs(true)},
284+
{"list_unwrap_no_none",
285+
"optional.unwrap([optional.of(42), optional.of(\"a\")]) == [42, "
286+
"\"a\"]",
287+
BoolValueIs(true)},
288+
{"list_unwrapOpt_empty", "[].unwrapOpt() == []", BoolValueIs(true)},
289+
{"list_unwrapOpt_empty_optional_none",
290+
"[optional.none(), optional.none()].unwrapOpt() == []",
291+
BoolValueIs(true)},
292+
{"list_unwrapOpt_three_elements",
293+
"[optional.of(42), optional.none(), "
294+
"optional.of(\"a\")].unwrapOpt() == [42, \"a\"]",
295+
BoolValueIs(true)},
296+
{"list_unwrapOpt_no_none",
297+
"[optional.of(42), optional.of(\"a\")].unwrapOpt() == [42, \"a\"]",
298+
BoolValueIs(true)},
299+
}),
275300
/*enable_short_circuiting*/ testing::Bool()));
276301

277302
class UnreachableFunction final : public cel::Function {

0 commit comments

Comments
 (0)