Skip to content

Commit f9b81a0

Browse files
dmitriplotnikovcopybara-github
authored andcommitted
Refactor CelExtensionLibrary to centralize version definitions.
This allows to have a better support when the extension library has multiple versions. Now the knowledge of all supported extension versions and which version is the latest is encapsulated inside the corresponding Cel*Extension class. PiperOrigin-RevId: 786864243
1 parent b870465 commit f9b81a0

7 files changed

Lines changed: 243 additions & 178 deletions

File tree

bundle/src/main/java/dev/cel/bundle/CelEnvironmentExporter.java

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
import dev.cel.expr.Decl.FunctionDecl.Overload;
2424
import com.google.auto.value.AutoValue;
2525
import com.google.common.collect.ArrayListMultimap;
26-
import com.google.common.collect.ImmutableList;
2726
import com.google.common.collect.ImmutableSet;
2827
import com.google.common.collect.ListMultimap;
2928
import com.google.errorprone.annotations.CanIgnoreReturnValue;
@@ -97,7 +96,8 @@ public abstract class CelEnvironmentExporter {
9796
*/
9897
abstract int maxExcludedStandardFunctionOverloads();
9998

100-
abstract ImmutableSet<CelExtensionLibrary> extensionLibraries();
99+
abstract ImmutableSet<CelExtensionLibrary<? extends CelExtensionLibrary.FeatureSet>>
100+
extensionLibraries();
101101

102102
/** Builder for {@link CelEnvironmentExporter}. */
103103
@AutoValue.Builder
@@ -107,22 +107,21 @@ public abstract static class Builder {
107107

108108
public abstract Builder setMaxExcludedStandardFunctionOverloads(int count);
109109

110-
abstract ImmutableSet.Builder<CelExtensionLibrary> extensionLibrariesBuilder();
110+
abstract ImmutableSet.Builder<CelExtensionLibrary<? extends CelExtensionLibrary.FeatureSet>>
111+
extensionLibrariesBuilder();
111112

112113
@CanIgnoreReturnValue
113114
public Builder addStandardExtensions(CelOptions options) {
114115
addExtensionLibraries(
115-
CelExtensions.math(options, 0),
116-
CelExtensions.math(options, 1),
117-
CelExtensions.math(options, 2),
118-
CelExtensions.lists(0),
119-
CelExtensions.lists(1),
120-
CelExtensions.lists(2));
116+
CelExtensions.getExtensionLibrary("math", options),
117+
CelExtensions.getExtensionLibrary("lists", options));
118+
// TODO: add support for remaining standard extensions
121119
return this;
122120
}
123121

124122
@CanIgnoreReturnValue
125-
public Builder addExtensionLibraries(CelExtensionLibrary... libraries) {
123+
public Builder addExtensionLibraries(
124+
CelExtensionLibrary<? extends CelExtensionLibrary.FeatureSet>... libraries) {
126125
extensionLibrariesBuilder().add(libraries);
127126
return this;
128127
}
@@ -216,52 +215,59 @@ public void visitMacro(CelMacro macro) {
216215
*/
217216
private void addExtensionConfigsAndRemoveFromInventory(
218217
CelEnvironment.Builder envBuilder, Set<Object> inventory) {
219-
ImmutableList<CelExtensionLibrary> libraries =
220-
ImmutableList.sortedCopyOf(
221-
Comparator.comparing(CelExtensionLibrary::getName)
222-
.thenComparing(CelExtensionLibrary::getVersion)
223-
.reversed(),
224-
extensionLibraries());
218+
ArrayList<NamedFeatureSet> featureSets = new ArrayList<>();
219+
220+
for (CelExtensionLibrary<? extends CelExtensionLibrary.FeatureSet> extensionLibrary :
221+
extensionLibraries()) {
222+
for (CelExtensionLibrary.FeatureSet featureSet : extensionLibrary.versions()) {
223+
featureSets.add(NamedFeatureSet.create(extensionLibrary.name(), featureSet));
224+
}
225+
}
226+
227+
featureSets.sort(
228+
Comparator.comparing(NamedFeatureSet::name)
229+
.thenComparing(nfs -> nfs.featureSet().version())
230+
.reversed());
225231

226232
Set<String> includedExtensions = new HashSet<>();
227-
for (CelExtensionLibrary library : libraries) {
228-
if (includedExtensions.contains(library.getName())) {
233+
for (NamedFeatureSet lib : featureSets) {
234+
if (includedExtensions.contains(lib.name())) {
229235
// We only need to infer the highest version library, so we can skip lower versions
230236
continue;
231237
}
232238

233-
if (checkIfExtensionIsIncludedAndRemoveFromInventory(inventory, library)) {
234-
envBuilder.addExtensions(ExtensionConfig.of(library.getName(), library.getVersion()));
235-
includedExtensions.add(library.getName());
239+
if (checkIfExtensionIsIncludedAndRemoveFromInventory(inventory, lib.featureSet())) {
240+
envBuilder.addExtensions(ExtensionConfig.of(lib.name(), lib.featureSet().version()));
241+
includedExtensions.add(lib.name());
236242
}
237243
}
238244
}
239245

240246
private boolean checkIfExtensionIsIncludedAndRemoveFromInventory(
241-
Set<Object> inventory, CelExtensionLibrary library) {
242-
ImmutableSet<CelFunctionDecl> functions = library.getFunctions();
243-
ArrayList<Object> includedItems = new ArrayList<>(functions.size());
247+
Set<Object> inventory, CelExtensionLibrary.FeatureSet featureSet) {
248+
ImmutableSet<CelFunctionDecl> functions = featureSet.functions();
249+
ArrayList<Object> includedFeatures = new ArrayList<>(functions.size());
244250
for (CelFunctionDecl function : functions) {
245251
for (CelOverloadDecl overload : function.overloads()) {
246-
NamedOverload item = NamedOverload.create(function.name(), overload);
247-
if (!inventory.contains(item)) {
252+
NamedOverload feature = NamedOverload.create(function.name(), overload);
253+
if (!inventory.contains(feature)) {
248254
return false;
249255
}
250-
includedItems.add(item);
256+
includedFeatures.add(feature);
251257
}
252258
}
253259

254-
ImmutableSet<CelMacro> macros = library.getMacros();
260+
ImmutableSet<CelMacro> macros = featureSet.macros();
255261
for (CelMacro macro : macros) {
256262
if (!inventory.contains(macro)) {
257263
return false;
258264
}
259-
includedItems.add(macro);
265+
includedFeatures.add(macro);
260266
}
261267

262268
// TODO - Add checks for variables.
263269

264-
inventory.removeAll(includedItems);
270+
inventory.removeAll(includedFeatures);
265271
return true;
266272
}
267273

@@ -424,5 +430,18 @@ static NamedOverload create(String functionName, CelOverloadDecl overload) {
424430
return new AutoValue_CelEnvironmentExporter_NamedOverload(functionName, overload);
425431
}
426432
}
427-
}
428433

434+
/**
435+
* Wrapper for CelExtensionLibrary.FeatureSet, associating it with the corresponding library name.
436+
*/
437+
@AutoValue
438+
abstract static class NamedFeatureSet {
439+
abstract String name();
440+
441+
abstract CelExtensionLibrary.FeatureSet featureSet();
442+
443+
static NamedFeatureSet create(String name, CelExtensionLibrary.FeatureSet featureSet) {
444+
return new AutoValue_CelEnvironmentExporter_NamedFeatureSet(name, featureSet);
445+
}
446+
}
447+
}

extensions/src/main/java/dev/cel/extensions/BUILD.bazel

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ java_library(
3939
":sets_function",
4040
":strings",
4141
"//common:options",
42+
"//extensions:extension_library",
4243
"@maven//:com_google_guava_guava",
4344
],
4445
)

extensions/src/main/java/dev/cel/extensions/CelExtensionLibrary.java

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,51 @@
1717
import com.google.common.collect.ImmutableSet;
1818
import dev.cel.common.CelFunctionDecl;
1919
import dev.cel.parser.CelMacro;
20+
import java.util.Comparator;
2021

2122
/**
2223
* Interface for defining CEL extension libraries.
2324
*
2425
* <p>An extension library is a collection of CEL functions, variables, and macros that can be added
2526
* to a CEL environment to provide additional functionality.
2627
*/
27-
public interface CelExtensionLibrary {
28+
public interface CelExtensionLibrary<T extends CelExtensionLibrary.FeatureSet> {
2829

2930
/** Returns the name of the extension library. */
30-
String getName();
31+
String name();
3132

32-
/** Returns the extension library version or -1 if unspecified. */
33-
int getVersion();
33+
ImmutableSet<T> versions();
3434

35-
/** Returns the set of function declarations defined by this extension library. */
36-
ImmutableSet<CelFunctionDecl> getFunctions();
35+
default T latest() {
36+
return versions().stream().max(Comparator.comparing(FeatureSet::version)).get();
37+
}
3738

38-
/** Returns the set of macros defined by this extension library. */
39-
ImmutableSet<CelMacro> getMacros();
39+
default T version(int version) {
40+
if (version == Integer.MAX_VALUE) {
41+
return latest();
42+
}
4043

41-
// TODO - Add a method for variables.
44+
for (T v : versions()) {
45+
if (v.version() == version) {
46+
return v;
47+
}
48+
}
49+
throw new IllegalArgumentException("Unsupported '" + name() + "' extension version " + version);
50+
}
51+
52+
/**
53+
* Interface for defining a version of a CEL extension library.
54+
*/
55+
interface FeatureSet {
56+
/** Returns the extension library version or -1 if unspecified. */
57+
int version();
58+
59+
/** Returns the set of function declarations defined by this extension library. */
60+
ImmutableSet<CelFunctionDecl> functions();
61+
62+
/** Returns the set of macros defined by this extension library. */
63+
ImmutableSet<CelMacro> macros();
64+
65+
// TODO - Add a method for variables.
66+
}
4267
}

extensions/src/main/java/dev/cel/extensions/CelExtensions.java

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import com.google.common.collect.ImmutableSet;
2121
import com.google.common.collect.Streams;
2222
import dev.cel.common.CelOptions;
23-
import dev.cel.extensions.CelListsExtensions.Function;
2423
import java.util.Set;
2524

2625
/**
@@ -108,7 +107,7 @@ public static CelProtoExtensions protos() {
108107
* options object used to configure the compilation/runtime environments.
109108
*/
110109
public static CelMathExtensions math(CelOptions celOptions) {
111-
return new CelMathExtensions(celOptions, Integer.MAX_VALUE);
110+
return CelMathExtensions.library(celOptions).latest();
112111
}
113112

114113
/**
@@ -117,7 +116,7 @@ public static CelMathExtensions math(CelOptions celOptions) {
117116
* <p>Refer to README.md for functions available in each version.
118117
*/
119118
public static CelMathExtensions math(CelOptions celOptions, int version) {
120-
return new CelMathExtensions(celOptions, version);
119+
return CelMathExtensions.library(celOptions).version(version);
121120
}
122121

123122
/**
@@ -229,7 +228,7 @@ public static CelSetsExtensions sets(CelOptions celOptions, Set<SetsFunction> fu
229228
* CelListsExtensions.Function}.
230229
*/
231230
public static CelListsExtensions lists() {
232-
return new CelListsExtensions(Integer.MAX_VALUE);
231+
return CelListsExtensions.library().latest();
233232
}
234233

235234
/**
@@ -238,7 +237,7 @@ public static CelListsExtensions lists() {
238237
* <p>Refer to README.md for functions available in each version.
239238
*/
240239
public static CelListsExtensions lists(int version) {
241-
return new CelListsExtensions(version);
240+
return CelListsExtensions.library().version(version);
242241
}
243242

244243
/**
@@ -259,8 +258,8 @@ public static CelListsExtensions lists(CelListsExtensions.Function... functions)
259258
* <p>Refer to README.md for available functions.
260259
*
261260
* <p>This will include all functions denoted in {@link CelListsExtensions.Function}, including
262-
* any future additions. To expose only a subset of functions, use {@link #lists(Function...)}
263-
* instead.
261+
* any future additions. To expose only a subset of functions, use {@link
262+
* #lists(CelListsExtensions.Function...)} instead.
264263
*/
265264
public static CelListsExtensions lists(Set<CelListsExtensions.Function> functions) {
266265
return new CelListsExtensions(functions);
@@ -301,5 +300,18 @@ public static ImmutableSet<String> getAllFunctionNames() {
301300
.collect(toImmutableSet());
302301
}
303302

303+
public static CelExtensionLibrary<? extends CelExtensionLibrary.FeatureSet> getExtensionLibrary(
304+
String name, CelOptions options) {
305+
switch (name) {
306+
case "math":
307+
return CelMathExtensions.library(options);
308+
case "lists":
309+
return CelListsExtensions.library();
310+
// TODO: add support for remaining standard extensions
311+
default:
312+
throw new IllegalArgumentException("Unknown standard extension '" + name + "'");
313+
}
314+
}
315+
304316
private CelExtensions() {}
305317
}

0 commit comments

Comments
 (0)