Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions common/typedef/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Copyright 2026 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")

package(default_visibility = ["//visibility:public"])

licenses(["notice"])

cc_library(
name = "typedef",
srcs = ["typedef.cc"],
hdrs = ["typedef.h"],
deps = [
"//common:ast",
"//common:constant",
"@com_google_absl//absl/base:core_headers",
"@com_google_absl//absl/base:nullability",
"@com_google_absl//absl/container:flat_hash_map",
"@com_google_absl//absl/functional:overload",
"@com_google_absl//absl/log:absl_check",
"@com_google_absl//absl/status",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:string_view",
],
)

cc_test(
name = "typedef_test",
srcs = ["typedef_test.cc"],
deps = [
":typedef",
"//common:ast",
"//common:constant",
"//internal:testing",
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:status_matchers",
],
)
81 changes: 81 additions & 0 deletions common/typedef/typedef.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "common/typedef/typedef.h"

#include <utility>
#include <variant>

#include "absl/base/nullability.h"
#include "absl/functional/overload.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"

namespace cel {

absl::Status StructTypeDef::AddField(Field field) {
if (field.name().empty()) {
return absl::InvalidArgumentError("Field name cannot be empty.");
}
if (FindField(field.name()) != nullptr) {
return absl::AlreadyExistsError(
absl::StrCat("Field '", field.name(), "' is already defined."));
}
fields_.push_back(std::move(field));
return absl::OkStatus();
}

const StructTypeDef::Field* absl_nullable StructTypeDef::FindField(
absl::string_view field_name) const {
for (const Field& field : fields_) {
if (field.name() == field_name) {
return &field;
}
}
return nullptr;
}

absl::Status EnumTypeDef::AddConstant(EnumConstant constant) {
if (constant.name().empty()) {
return absl::InvalidArgumentError("Enum constant name cannot be empty.");
}
if (FindConstant(constant.name()) != nullptr) {
return absl::AlreadyExistsError(absl::StrCat(
"Enum constant '", constant.name(), "' is already defined."));
}
constants_.push_back(std::move(constant));
return absl::OkStatus();
}

const EnumTypeDef::EnumConstant* absl_nullable EnumTypeDef::FindConstant(
absl::string_view constant_name) const {
for (const EnumConstant& constant : constants_) {
if (constant.name() == constant_name) {
return &constant;
}
}
return nullptr;
}

TypeDefKindCase TypeDef::kind_case() const {
return std::visit(
absl::Overload{
[](const StructTypeDef&) { return TypeDefKindCase::kStruct; },
[](const EnumTypeDef&) { return TypeDefKindCase::kEnum; },
},
variant_);
}

} // namespace cel
212 changes: 212 additions & 0 deletions common/typedef/typedef.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef THIRD_PARTY_CEL_CPP_COMMON_TYPEDEF_TYPEDEF_H_
#define THIRD_PARTY_CEL_CPP_COMMON_TYPEDEF_TYPEDEF_H_

#include <any>
#include <cstdint>
#include <string>
#include <utility>
#include <variant>
#include <vector>

#include "absl/base/attributes.h"
#include "absl/base/nullability.h"
#include "absl/container/flat_hash_map.h"
#include "absl/log/absl_check.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "common/ast.h"
#include "common/constant.h"

namespace cel {

// Represents a struct type with typed fields.
class StructTypeDef {
public:
class Field {
public:
Field() = default;
Field(std::string name, TypeSpec type, std::string doc = "",
Constant default_value = {},
absl::flat_hash_map<std::string, std::any>
schema_specific_properties = {})
: name_(std::move(name)),
type_(std::move(type)),
doc_(std::move(doc)),
default_value_(std::move(default_value)),
schema_specific_properties_(std::move(schema_specific_properties)) {}

absl::string_view name() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return name_;
}
const TypeSpec& type() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return type_; }
absl::string_view doc() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return doc_; }
// Optional scalar default value; check `default_value().has_value()`.
// When the field type is an enum type, `default_value` is the name of the
// corresponding `EnumConstant`.
const Constant& default_value() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return default_value_;
}
// Target schema-specific properties keyed by target schema name.
const absl::flat_hash_map<std::string, std::any>&
schema_specific_properties() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return schema_specific_properties_;
}

private:
std::string name_;
TypeSpec type_;
std::string doc_;
Constant default_value_;
absl::flat_hash_map<std::string, std::any> schema_specific_properties_;
};

StructTypeDef() = default;
explicit StructTypeDef(std::string name, std::string doc = "",
absl::flat_hash_map<std::string, std::any>
schema_specific_properties = {})
: name_(std::move(name)),
doc_(std::move(doc)),
schema_specific_properties_(std::move(schema_specific_properties)) {}

absl::string_view name() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return name_; }
absl::string_view doc() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return doc_; }
const std::vector<Field>& fields() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return fields_;
}
// Target schema-specific properties keyed by target schema name.
const absl::flat_hash_map<std::string, std::any>& schema_specific_properties()
const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return schema_specific_properties_;
}

// Adds a field to the struct definition. Field names must be non-empty and
// unique.
absl::Status AddField(Field field);
const Field* absl_nullable FindField(absl::string_view field_name) const
ABSL_ATTRIBUTE_LIFETIME_BOUND;

private:
std::string name_;
std::string doc_;
std::vector<Field> fields_;
absl::flat_hash_map<std::string, std::any> schema_specific_properties_;
};

// Represents a named enumeration type with named and numbered constants.
class EnumTypeDef {
public:
class EnumConstant {
public:
EnumConstant() = default;
explicit EnumConstant(std::string name, int32_t id = 0,
std::string doc = "",
absl::flat_hash_map<std::string, std::any>
schema_specific_properties = {})
: name_(std::move(name)),
id_(id),
doc_(std::move(doc)),
schema_specific_properties_(std::move(schema_specific_properties)) {}

absl::string_view name() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return name_;
}
int32_t id() const { return id_; }
absl::string_view doc() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return doc_; }
// Target schema-specific properties keyed by target schema name.
const absl::flat_hash_map<std::string, std::any>&
schema_specific_properties() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return schema_specific_properties_;
}

private:
std::string name_;
int32_t id_ = 0;
std::string doc_;
absl::flat_hash_map<std::string, std::any> schema_specific_properties_;
};

EnumTypeDef() = default;
explicit EnumTypeDef(std::string name, std::string doc = "",
absl::flat_hash_map<std::string, std::any>
schema_specific_properties = {})
: name_(std::move(name)),
doc_(std::move(doc)),
schema_specific_properties_(std::move(schema_specific_properties)) {}

absl::string_view name() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return name_; }
absl::string_view doc() const ABSL_ATTRIBUTE_LIFETIME_BOUND { return doc_; }
const std::vector<EnumConstant>& constants() const
ABSL_ATTRIBUTE_LIFETIME_BOUND {
return constants_;
}
// Target schema-specific properties keyed by target schema name.
const absl::flat_hash_map<std::string, std::any>& schema_specific_properties()
const ABSL_ATTRIBUTE_LIFETIME_BOUND {
return schema_specific_properties_;
}

// Adds a constant to the enum definition. Constant names must be non-empty
// and unique; numeric IDs may alias.
absl::Status AddConstant(EnumConstant constant);
const EnumConstant* absl_nullable FindConstant(
absl::string_view constant_name) const ABSL_ATTRIBUTE_LIFETIME_BOUND;

private:
std::string name_;
std::string doc_;
std::vector<EnumConstant> constants_;
absl::flat_hash_map<std::string, std::any> schema_specific_properties_;
};

enum class TypeDefKindCase {
kStruct,
kEnum,
};

// Variant wrapper holding either a StructTypeDef or EnumTypeDef.
class TypeDef {
public:
TypeDef() = default;
explicit TypeDef(StructTypeDef struct_type)
: variant_(std::move(struct_type)) {}
explicit TypeDef(EnumTypeDef enum_type) : variant_(std::move(enum_type)) {}

TypeDefKindCase kind_case() const;

bool is_struct() const {
return std::holds_alternative<StructTypeDef>(variant_);
}
// REQUIRES: `is_struct()` is true.
const StructTypeDef& struct_type() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_DCHECK(is_struct());
return std::get<StructTypeDef>(variant_);
}

bool is_enum() const { return std::holds_alternative<EnumTypeDef>(variant_); }
// REQUIRES: `is_enum()` is true.
const EnumTypeDef& enum_type() const ABSL_ATTRIBUTE_LIFETIME_BOUND {
ABSL_DCHECK(is_enum());
return std::get<EnumTypeDef>(variant_);
}

private:
std::variant<StructTypeDef, EnumTypeDef> variant_;
};

} // namespace cel

#endif // THIRD_PARTY_CEL_CPP_COMMON_TYPEDEF_TYPEDEF_H_
Loading
Loading