Coverage Report

Created: 2026-10-09 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/eval/eval/create_struct_step.cc
Line
Count
Source
1
// Copyright 2017 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 "eval/eval/create_struct_step.h"
16
17
#include <cstdint>
18
#include <memory>
19
#include <string>
20
#include <utility>
21
#include <vector>
22
23
#include "absl/container/flat_hash_set.h"
24
#include "absl/status/status.h"
25
#include "absl/status/statusor.h"
26
#include "absl/strings/str_cat.h"
27
#include "absl/strings/string_view.h"
28
#include "absl/types/optional.h"
29
#include "common/value.h"
30
#include "eval/eval/evaluator_core.h"
31
#include "eval/eval/expression_step_base.h"
32
#include "eval/eval/expression_step_logic.h"
33
#include "internal/status_macros.h"
34
35
namespace google::api::expr::runtime {
36
37
namespace {
38
39
using ::cel::ErrorValue;
40
using ::cel::StructValueBuilderInterface;
41
using ::cel::UnknownValue;
42
using ::cel::Value;
43
44
// `CreateStruct` implementation for message/struct.
45
class CreateStructStepForStruct final : public ExpressionStepBase {
46
 public:
47
  CreateStructStepForStruct(std::string name, std::vector<std::string> entries,
48
                            absl::flat_hash_set<int32_t> optional_indices)
49
2.56k
      : ExpressionStepBase(),
50
2.56k
        name_(std::move(name)),
51
2.56k
        entries_(std::move(entries)),
52
2.56k
        optional_indices_(std::move(optional_indices)) {}
53
54
  void Evaluate(ExecutionFrame* frame) const override;
55
56
 private:
57
  absl::StatusOr<Value> DoEvaluate(ExecutionFrame* frame) const;
58
59
  std::string name_;
60
  std::vector<std::string> entries_;
61
  absl::flat_hash_set<int32_t> optional_indices_;
62
};
63
64
absl::StatusOr<Value> CreateStructStepForStruct::DoEvaluate(
65
1.02M
    ExecutionFrame* frame) const {
66
1.02M
  int entries_size = entries_.size();
67
68
1.02M
  auto args = frame->value_stack().GetSpan(entries_size);
69
70
1.02M
  for (const auto& arg : args) {
71
480k
    if (arg.IsError()) {
72
49.6k
      return arg;
73
49.6k
    }
74
480k
  }
75
76
975k
  if (frame->enable_unknowns()) {
77
0
    absl::optional<UnknownValue> unknown_set =
78
0
        frame->attribute_utility().IdentifyAndMergeUnknowns(
79
0
            args, frame->value_stack().GetAttributeSpan(entries_size),
80
0
            /*use_partial=*/true);
81
0
    if (unknown_set.has_value()) {
82
0
      return *unknown_set;
83
0
    }
84
0
  }
85
86
1.95M
  CEL_ASSIGN_OR_RETURN(auto builder,
87
1.95M
                       frame->type_provider().NewValueBuilder(
88
1.95M
                           name_, frame->message_factory(), frame->arena()));
89
1.95M
  if (builder == nullptr) {
90
25.1k
    return ErrorValue::From(
91
25.1k
        absl::NotFoundError(absl::StrCat("Unable to find builder: ", name_)),
92
25.1k
        frame->arena());
93
25.1k
  }
94
95
1.35M
  for (int i = 0; i < entries_size; ++i) {
96
431k
    const auto& entry = entries_[i];
97
431k
    const auto& arg = args[i];
98
431k
    if (optional_indices_.contains(static_cast<int32_t>(i))) {
99
0
      if (auto optional_arg = arg.AsOptional(); optional_arg) {
100
0
        if (!optional_arg->HasValue()) {
101
0
          continue;
102
0
        }
103
0
        Value optional_arg_value;
104
0
        optional_arg->Value(&optional_arg_value);
105
0
        if (optional_arg_value.IsError()) {
106
          // Error should never be in optional, but better safe than sorry.
107
0
          return optional_arg_value;
108
0
        }
109
0
        CEL_ASSIGN_OR_RETURN(
110
0
            absl::optional<ErrorValue> error_value,
111
0
            builder->SetFieldByName(entry, std::move(optional_arg_value)));
112
0
        if (error_value) {
113
0
          return std::move(*error_value);
114
0
        }
115
0
      } else {
116
0
        return cel::TypeConversionError(arg.DebugString(), "optional_type",
117
0
                                        frame->arena());
118
0
      }
119
431k
    } else {
120
431k
      CEL_ASSIGN_OR_RETURN(absl::optional<ErrorValue> error_value,
121
431k
                           builder->SetFieldByName(entry, arg));
122
431k
      if (error_value) {
123
29.5k
        return std::move(*error_value);
124
29.5k
      }
125
431k
    }
126
431k
  }
127
128
920k
  return std::move(*builder).Build();
129
950k
}
130
131
1.02M
void CreateStructStepForStruct::Evaluate(ExecutionFrame* frame) const {
132
1.02M
  if (frame->value_stack().size() < entries_.size()) {
133
0
    frame->Abort(
134
0
        absl::InternalError("CreateStructStepForStruct: stack underflow"));
135
0
    return;
136
0
  }
137
1.02M
  absl::StatusOr<Value> result = DoEvaluate(frame);
138
1.02M
  if (!result.ok()) {
139
106
    frame->Abort(std::move(result).status());
140
106
    return;
141
106
  }
142
1.02M
  frame->value_stack().PopAndPush(entries_.size(), *std::move(result));
143
1.02M
}
144
145
}  // namespace
146
147
std::unique_ptr<ExpressionStepLogic> CreateCreateStructStep(
148
    std::string name, std::vector<std::string> field_keys,
149
2.56k
    absl::flat_hash_set<int32_t> optional_indices) {
150
  // MakeOptionalIndicesSet(create_struct_expr)
151
2.56k
  return std::make_unique<CreateStructStepForStruct>(
152
2.56k
      std::move(name), std::move(field_keys), std::move(optional_indices));
153
2.56k
}
154
}  // namespace google::api::expr::runtime