Skip to content

Commit 339046b

Browse files
dmitriplotnikovcopybara-github
authored andcommitted
[cel-types] Add YAML encoding and decoding for CEL TypeDef and Schema properties.
Introduce `SchemaYaml` and `SchemaYamlRegistry` in `common/typedef/schema_yaml` for pluggable YAML encoding and decoding of target-schema-specific properties. Implement `TypeDefFromYaml`, `TypeDefsFromYaml`, `TypeDefToYaml`, and `TypeDefsToYaml` in `common/typedef/typedef_yaml`, supporting both concise type signatures (`list<string>`) and structured `TypeSpec` representations as well as delegating `schemas` blocks to registered `SchemaYaml` codecs. PiperOrigin-RevId: 993955156
1 parent 9c562a3 commit 339046b

14 files changed

Lines changed: 4456 additions & 0 deletions

‎common/typedef/BUILD‎

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Copyright 2026 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+
load("@rules_cc//cc:cc_library.bzl", "cc_library")
16+
load("@rules_cc//cc:cc_test.bzl", "cc_test")
17+
18+
package(default_visibility = ["//visibility:public"])
19+
20+
licenses(["notice"])
21+
22+
cc_library(
23+
name = "typedef",
24+
srcs = ["typedef.cc"],
25+
hdrs = ["typedef.h"],
26+
deps = [
27+
"//common:ast",
28+
"//common:constant",
29+
"@com_google_absl//absl/base:core_headers",
30+
"@com_google_absl//absl/base:nullability",
31+
"@com_google_absl//absl/container:flat_hash_map",
32+
"@com_google_absl//absl/functional:overload",
33+
"@com_google_absl//absl/log:absl_check",
34+
"@com_google_absl//absl/status",
35+
"@com_google_absl//absl/strings",
36+
"@com_google_absl//absl/strings:string_view",
37+
],
38+
)
39+
40+
cc_test(
41+
name = "typedef_test",
42+
srcs = ["typedef_test.cc"],
43+
deps = [
44+
":typedef",
45+
"//common:ast",
46+
"//common:constant",
47+
"//internal:testing",
48+
"@com_google_absl//absl/status",
49+
"@com_google_absl//absl/status:status_matchers",
50+
],
51+
)
52+
53+
# NOTE: The YAML targets below depend on yaml-cpp (//third_party/yamlcpp),
54+
# which is used for open-source CEL compatibility (and therefore cannot be
55+
# trivially migrated to Crubit/Rust YAML parsers) and requires C++ exceptions.
56+
# The implementation using //third_party/yamlcpp carefully catches and handles
57+
# exceptions, so code using these targets does not need the -fexceptions flag.
58+
59+
cc_library(
60+
name = "yaml_helpers",
61+
srcs = ["yaml_helpers.cc"],
62+
hdrs = ["yaml_helpers.h"],
63+
copts = ["-fexceptions"],
64+
features = ["-use_header_modules"],
65+
deps = [
66+
"@com_google_absl//absl/status",
67+
"@com_google_absl//absl/status:statusor",
68+
"@com_google_absl//absl/strings",
69+
"@com_google_absl//absl/strings:string_view",
70+
"@yaml-cpp",
71+
],
72+
)
73+
74+
cc_library(
75+
name = "schema_yaml",
76+
srcs = ["schema_yaml.cc"],
77+
hdrs = ["schema_yaml.h"],
78+
deps = [
79+
":yaml_helpers",
80+
"@com_google_absl//absl/base:nullability",
81+
"@com_google_absl//absl/container:flat_hash_map",
82+
"@com_google_absl//absl/status",
83+
"@com_google_absl//absl/status:statusor",
84+
"@com_google_absl//absl/strings",
85+
"@com_google_absl//absl/strings:string_view",
86+
],
87+
)
88+
89+
cc_test(
90+
name = "schema_yaml_test",
91+
srcs = ["schema_yaml_test.cc"],
92+
copts = ["-fexceptions"],
93+
features = ["-use_header_modules"],
94+
deps = [
95+
":schema_yaml",
96+
"//internal:testing",
97+
"@com_google_absl//absl/status",
98+
"@com_google_absl//absl/status:status_matchers",
99+
"@com_google_absl//absl/strings:string_view",
100+
"@yaml-cpp",
101+
],
102+
)
103+
104+
cc_library(
105+
name = "typedef_yaml",
106+
srcs = ["typedef_yaml.cc"],
107+
hdrs = [
108+
"typedef_yaml.h",
109+
],
110+
copts = ["-fexceptions"],
111+
features = ["-use_header_modules"],
112+
deps = [
113+
":schema_yaml",
114+
":typedef",
115+
":yaml_helpers",
116+
"//common:ast",
117+
"//common:constant",
118+
"//common:signature",
119+
"//internal:status_macros",
120+
"//internal:strings",
121+
"@com_google_absl//absl/algorithm:container",
122+
"@com_google_absl//absl/base:nullability",
123+
"@com_google_absl//absl/container:flat_hash_map",
124+
"@com_google_absl//absl/status",
125+
"@com_google_absl//absl/status:statusor",
126+
"@com_google_absl//absl/strings",
127+
"@com_google_absl//absl/strings:str_format",
128+
"@com_google_absl//absl/strings:string_view",
129+
"@com_google_absl//absl/time",
130+
"@com_google_absl//absl/types:span",
131+
"@yaml-cpp",
132+
],
133+
)
134+
135+
cc_test(
136+
name = "typedef_yaml_test",
137+
srcs = ["typedef_yaml_test.cc"],
138+
copts = ["-fexceptions"],
139+
features = ["-use_header_modules"],
140+
deps = [
141+
":schema_yaml",
142+
":typedef",
143+
":typedef_yaml",
144+
":yaml_helpers",
145+
":yaml_test_helpers",
146+
"//common:ast",
147+
"//common:constant",
148+
"//internal:status_macros",
149+
"//internal:testing",
150+
"@com_google_absl//absl/status",
151+
"@com_google_absl//absl/status:status_matchers",
152+
"@com_google_absl//absl/status:statusor",
153+
"@com_google_absl//absl/strings",
154+
"@com_google_absl//absl/strings:string_view",
155+
"@com_google_absl//absl/time",
156+
"@yaml-cpp",
157+
],
158+
)
159+
160+
cc_library(
161+
name = "yaml_test_helpers",
162+
testonly = True,
163+
srcs = ["yaml_test_helpers.cc"],
164+
hdrs = ["yaml_test_helpers.h"],
165+
deps = [
166+
"@com_google_absl//absl/strings",
167+
"@com_google_absl//absl/strings:string_view",
168+
],
169+
)

‎common/typedef/schema_yaml.cc‎

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Copyright 2026 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 "common/typedef/schema_yaml.h"
16+
17+
#include <any>
18+
#include <memory>
19+
#include <utility>
20+
#include <vector>
21+
22+
#include "absl/base/nullability.h"
23+
#include "absl/status/status.h"
24+
#include "absl/status/statusor.h"
25+
#include "absl/strings/str_cat.h"
26+
#include "absl/strings/string_view.h"
27+
#include "common/typedef/yaml_helpers.h"
28+
29+
namespace cel {
30+
31+
absl::StatusOr<std::any> SchemaYaml::DecodeStructProperties(
32+
absl::string_view yaml, const YAML::Node& node) const {
33+
if (typedef_internal::IsEmptyYamlNode(node)) {
34+
return std::any();
35+
}
36+
return typedef_internal::YamlError(
37+
yaml, node,
38+
absl::StrCat("Custom struct properties are not supported for schema '",
39+
name(), "'"));
40+
}
41+
42+
absl::StatusOr<std::any> SchemaYaml::DecodeFieldProperties(
43+
absl::string_view yaml, const YAML::Node& node) const {
44+
if (typedef_internal::IsEmptyYamlNode(node)) {
45+
return std::any();
46+
}
47+
return typedef_internal::YamlError(
48+
yaml, node,
49+
absl::StrCat("Custom field properties are not supported for schema '",
50+
name(), "'"));
51+
}
52+
53+
absl::StatusOr<std::any> SchemaYaml::DecodeEnumProperties(
54+
absl::string_view yaml, const YAML::Node& node) const {
55+
if (typedef_internal::IsEmptyYamlNode(node)) {
56+
return std::any();
57+
}
58+
return typedef_internal::YamlError(
59+
yaml, node,
60+
absl::StrCat("Custom enum properties are not supported for schema '",
61+
name(), "'"));
62+
}
63+
64+
absl::StatusOr<std::any> SchemaYaml::DecodeEnumConstantProperties(
65+
absl::string_view yaml, const YAML::Node& node) const {
66+
if (typedef_internal::IsEmptyYamlNode(node)) {
67+
return std::any();
68+
}
69+
return typedef_internal::YamlError(
70+
yaml, node,
71+
absl::StrCat(
72+
"Custom enum constant properties are not supported for schema '",
73+
name(), "'"));
74+
}
75+
76+
absl::Status SchemaYaml::EncodeStructProperties(const std::any& properties,
77+
YAML::Emitter& out) const {
78+
return absl::UnimplementedError(absl::StrCat(
79+
"Custom struct properties are not supported for schema '", name(), "'"));
80+
}
81+
82+
absl::Status SchemaYaml::EncodeFieldProperties(const std::any& properties,
83+
YAML::Emitter& out) const {
84+
return absl::UnimplementedError(absl::StrCat(
85+
"Custom field properties are not supported for schema '", name(), "'"));
86+
}
87+
88+
absl::Status SchemaYaml::EncodeEnumProperties(const std::any& properties,
89+
YAML::Emitter& out) const {
90+
return absl::UnimplementedError(absl::StrCat(
91+
"Custom enum properties are not supported for schema '", name(), "'"));
92+
}
93+
94+
absl::Status SchemaYaml::EncodeEnumConstantProperties(
95+
const std::any& properties, YAML::Emitter& out) const {
96+
return absl::UnimplementedError(absl::StrCat(
97+
"Custom enum constant properties are not supported for schema '", name(),
98+
"'"));
99+
}
100+
101+
SchemaYamlRegistry::SchemaYamlRegistry(
102+
std::vector<std::unique_ptr<const SchemaYaml>> schemas) {
103+
schemas_.reserve(schemas.size());
104+
for (std::unique_ptr<const SchemaYaml>& schema : schemas) {
105+
Add(std::move(schema));
106+
}
107+
}
108+
109+
const SchemaYaml* absl_nullable SchemaYamlRegistry::Find(
110+
absl::string_view schema_name) const {
111+
auto it = schemas_.find(schema_name);
112+
if (it == schemas_.end()) {
113+
return nullptr;
114+
}
115+
return it->second.get();
116+
}
117+
118+
} // namespace cel

‎common/typedef/schema_yaml.h‎

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Copyright 2026 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_COMMON_TYPEDEF_SCHEMA_YAML_H_
16+
#define THIRD_PARTY_CEL_CPP_COMMON_TYPEDEF_SCHEMA_YAML_H_
17+
18+
#include <any>
19+
#include <memory>
20+
#include <string>
21+
#include <type_traits>
22+
#include <utility>
23+
#include <vector>
24+
25+
#include "absl/base/nullability.h"
26+
#include "absl/container/flat_hash_map.h"
27+
#include "absl/status/status.h"
28+
#include "absl/status/statusor.h"
29+
#include "absl/strings/string_view.h"
30+
31+
namespace YAML {
32+
class Emitter;
33+
class Node;
34+
} // namespace YAML
35+
36+
namespace cel {
37+
38+
// Interface representing a YAML codec for a schema (e.g. "json",
39+
// "proto2", "proto3") capable of decoding and encoding schema-specific property
40+
// objects.
41+
class SchemaYaml {
42+
public:
43+
virtual ~SchemaYaml() = default;
44+
45+
// Returns the unique schema identifier (e.g. "json", "proto2", "proto3").
46+
virtual absl::string_view name() const = 0;
47+
48+
virtual absl::StatusOr<std::any> DecodeStructProperties(
49+
absl::string_view yaml, const YAML::Node& node) const;
50+
51+
virtual absl::StatusOr<std::any> DecodeFieldProperties(
52+
absl::string_view yaml, const YAML::Node& node) const;
53+
54+
virtual absl::StatusOr<std::any> DecodeEnumProperties(
55+
absl::string_view yaml, const YAML::Node& node) const;
56+
57+
virtual absl::StatusOr<std::any> DecodeEnumConstantProperties(
58+
absl::string_view yaml, const YAML::Node& node) const;
59+
60+
virtual absl::Status EncodeStructProperties(const std::any& properties,
61+
YAML::Emitter& out) const;
62+
63+
virtual absl::Status EncodeFieldProperties(const std::any& properties,
64+
YAML::Emitter& out) const;
65+
66+
virtual absl::Status EncodeEnumProperties(const std::any& properties,
67+
YAML::Emitter& out) const;
68+
69+
virtual absl::Status EncodeEnumConstantProperties(const std::any& properties,
70+
YAML::Emitter& out) const;
71+
};
72+
73+
// Read-only registry of SchemaYaml codecs keyed by schema name.
74+
class SchemaYamlRegistry {
75+
public:
76+
SchemaYamlRegistry() = default;
77+
78+
explicit SchemaYamlRegistry(
79+
std::vector<std::unique_ptr<const SchemaYaml>> schemas);
80+
81+
template <
82+
typename... Schemas,
83+
typename = std::enable_if_t<
84+
(sizeof...(Schemas) > 0) &&
85+
(std::is_convertible_v<Schemas, std::unique_ptr<const SchemaYaml>> &&
86+
...)>>
87+
explicit SchemaYamlRegistry(Schemas&&... schemas) {
88+
schemas_.reserve(sizeof...(Schemas));
89+
(Add(std::forward<Schemas>(schemas)), ...);
90+
}
91+
92+
// Finds a registered SchemaYaml by name, or returns nullptr if not
93+
// found.
94+
const SchemaYaml* absl_nullable Find(absl::string_view schema_name) const;
95+
96+
private:
97+
void Add(std::unique_ptr<const SchemaYaml> schema) {
98+
if (schema != nullptr) {
99+
absl::string_view name = schema->name();
100+
schemas_[name] = std::move(schema);
101+
}
102+
}
103+
104+
absl::flat_hash_map<std::string, std::unique_ptr<const SchemaYaml>> schemas_;
105+
};
106+
107+
} // namespace cel
108+
109+
#endif // THIRD_PARTY_CEL_CPP_COMMON_TYPEDEF_SCHEMA_YAML_H_

0 commit comments

Comments
 (0)