Coverage Report

Created: 2026-05-27 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/proc/self/cwd/runtime/internal/runtime_env.h
Line
Count
Source
1
// Copyright 2024 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
#ifndef THIRD_PARTY_CEL_CPP_RUNTIME_INTERNAL_RUNTIME_ENV_H_
16
#define THIRD_PARTY_CEL_CPP_RUNTIME_INTERNAL_RUNTIME_ENV_H_
17
18
#include <atomic>
19
#include <deque>
20
#include <memory>
21
#include <utility>
22
23
#include "absl/base/attributes.h"
24
#include "absl/base/nullability.h"
25
#include "absl/base/thread_annotations.h"
26
#include "absl/status/status.h"
27
#include "absl/synchronization/mutex.h"
28
#include "eval/public/cel_function_registry.h"
29
#include "eval/public/cel_type_registry.h"
30
#include "internal/well_known_types.h"
31
#include "runtime/function_registry.h"
32
#include "runtime/type_registry.h"
33
#include "google/protobuf/descriptor.h"
34
#include "google/protobuf/message.h"
35
36
namespace cel::runtime_internal {
37
38
// Shared state used by the runtime during creation, configuration, planning,
39
// and evaluation. Passed around via `std::shared_ptr`.
40
//
41
// TODO(uncreated-issue/66): Make this a class.
42
struct RuntimeEnv final {
43
  explicit RuntimeEnv(absl_nonnull std::shared_ptr<const google::protobuf::DescriptorPool>
44
                          descriptor_pool,
45
                      absl_nullable std::shared_ptr<google::protobuf::MessageFactory>
46
                          message_factory = nullptr)
47
14.5k
      : descriptor_pool(std::move(descriptor_pool)),
48
14.5k
        message_factory(std::move(message_factory)),
49
14.5k
        legacy_type_registry(this->descriptor_pool.get(),
50
14.5k
                             this->message_factory.get()),
51
14.5k
        type_registry(legacy_type_registry.InternalGetModernRegistry()),
52
14.5k
        function_registry(legacy_function_registry.InternalGetRegistry()) {
53
14.5k
    if (this->message_factory != nullptr) {
54
14.5k
      message_factory_ptr.store(this->message_factory.get(),
55
14.5k
                                std::memory_order_seq_cst);
56
14.5k
    }
57
14.5k
  }
58
59
  // Not copyable or moveable.
60
  RuntimeEnv(const RuntimeEnv&) = delete;
61
  RuntimeEnv(RuntimeEnv&&) = delete;
62
  RuntimeEnv& operator=(const RuntimeEnv&) = delete;
63
  RuntimeEnv& operator=(RuntimeEnv&&) = delete;
64
65
  // Ideally the environment would already be initialized, but things are a bit
66
  // awkward. This should only be called once immediately after construction.
67
14.5k
  absl::Status Initialize() {
68
14.5k
    return well_known_types.Initialize(descriptor_pool.get());
69
14.5k
  }
70
71
0
  bool IsInitialized() const { return well_known_types.IsInitialized(); }
72
73
  ABSL_ATTRIBUTE_UNUSED
74
  const absl_nonnull std::shared_ptr<const google::protobuf::DescriptorPool>
75
      descriptor_pool;
76
77
 private:
78
  // These fields deal with a message factory that is lazily initialized as
79
  // needed. This might be called during the planning phase of an expression or
80
  // during evaluation. We want the ability to get the message factory when it
81
  // is already created to be cheap, so we use an atomic and a mutex for the
82
  // slow path.
83
  //
84
  // Do not access any of these fields directly, use member functions.
85
  mutable absl::Mutex message_factory_mutex;
86
  mutable absl_nullable std::shared_ptr<google::protobuf::MessageFactory> message_factory
87
      ABSL_GUARDED_BY(message_factory_mutex);
88
  // std::atomic<std::shared_ptr<?>> is not really a simple atomic, so we
89
  // avoid it.
90
  mutable std::atomic<google::protobuf::MessageFactory* absl_nullable>
91
      message_factory_ptr = nullptr;
92
93
  struct KeepAlives final {
94
14.5k
    KeepAlives() = default;
95
96
    ~KeepAlives();
97
98
    // Not copyable or moveable.
99
    KeepAlives(const KeepAlives&) = delete;
100
    KeepAlives(KeepAlives&&) = delete;
101
    KeepAlives& operator=(const KeepAlives&) = delete;
102
    KeepAlives& operator=(KeepAlives&&) = delete;
103
104
    std::deque<std::shared_ptr<const void>> deque;
105
  };
106
107
  KeepAlives keep_alives;
108
109
 public:
110
  // Because of legacy shenanigans, we use shared_ptr here. For legacy, this is
111
  // an unowned shared_ptr (a noop deleter) pointing to the modern equivalent
112
  // which is a member of the legacy variant.
113
  google::api::expr::runtime::CelTypeRegistry legacy_type_registry;
114
  google::api::expr::runtime::CelFunctionRegistry legacy_function_registry;
115
  TypeRegistry& type_registry;
116
  FunctionRegistry& function_registry;
117
118
  well_known_types::Reflection well_known_types;
119
120
  google::protobuf::MessageFactory* absl_nonnull MutableMessageFactory() const
121
      ABSL_ATTRIBUTE_LIFETIME_BOUND;
122
123
  // Not thread safe. Adds `keep_alive` to a list owned by this environment
124
  // and ensures it survives at least as long as this environment. Keep alives
125
  // are released in reverse order of their registration. This mimics normal
126
  // destructor rules of members.
127
  //
128
  // IMPORTANT: This should only be when building the runtime, and not after.
129
  void KeepAlive(std::shared_ptr<const void> keep_alive);
130
};
131
132
}  // namespace cel::runtime_internal
133
134
#endif  // THIRD_PARTY_CEL_CPP_RUNTIME_INTERNAL_RUNTIME_ENV_H_