Skip to content

Commit

Permalink
Improve model and evaluation of conditions
Browse files Browse the repository at this point in the history
  • Loading branch information
adams85 committed Sep 7, 2023
1 parent 121290c commit 4171dbb
Show file tree
Hide file tree
Showing 9 changed files with 82 additions and 70 deletions.
10 changes: 5 additions & 5 deletions benchmarks/NewVersionLib/BenchmarkHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class BasicMatrixTestsDescriptor : IMatrixTestDescriptor
{
Conditions = new[]
{
new ConditionWrapper
new ConditionContainer
{
ComparisonCondition = new ComparisonCondition()
{
Expand All @@ -55,7 +55,7 @@ public class BasicMatrixTestsDescriptor : IMatrixTestDescriptor
{
Conditions = new[]
{
new ConditionWrapper
new ConditionContainer
{
ComparisonCondition = new ComparisonCondition()
{
Expand All @@ -71,7 +71,7 @@ public class BasicMatrixTestsDescriptor : IMatrixTestDescriptor
{
Conditions = new[]
{
new ConditionWrapper
new ConditionContainer
{
ComparisonCondition = new ComparisonCondition()
{
Expand All @@ -87,7 +87,7 @@ public class BasicMatrixTestsDescriptor : IMatrixTestDescriptor
{
Conditions = new[]
{
new ConditionWrapper
new ConditionContainer
{
ComparisonCondition = new ComparisonCondition()
{
Expand All @@ -103,7 +103,7 @@ public class BasicMatrixTestsDescriptor : IMatrixTestDescriptor
{
Conditions = new[]
{
new ConditionWrapper
new ConditionContainer
{
ComparisonCondition = new ComparisonCondition()
{
Expand Down
9 changes: 5 additions & 4 deletions src/ConfigCatClient/Evaluation/EvaluateLogHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,8 @@ public static IndentedTextBuilder AppendConditionConsequence(this IndentedTextBu
return result ? builder : builder.Append(", skipping the remaining AND conditions");
}

private static IndentedTextBuilder AppendConditions<TCondition>(this IndentedTextBuilder builder, TCondition[] conditions, Func<TCondition, ICondition?> getCondition)
private static IndentedTextBuilder AppendConditions<TCondition>(this IndentedTextBuilder builder, TCondition[] conditions)
where TCondition : IConditionProvider
{
for (var i = 0; i < conditions.Length; i++)
{
Expand All @@ -147,7 +148,7 @@ private static IndentedTextBuilder AppendConditions<TCondition>(this IndentedTex
builder.NewLine("AND ");
}

_ = getCondition(conditions[i]) switch
_ = conditions[i].GetCondition(throwIfInvalid: false) switch
{
ComparisonCondition comparisonCondition => builder.AppendComparisonCondition(comparisonCondition),
PrerequisiteFlagCondition prerequisiteFlagCondition => builder.AppendPrerequisiteFlagCondition(prerequisiteFlagCondition),
Expand Down Expand Up @@ -229,7 +230,7 @@ public static IndentedTextBuilder AppendTargetingRule(this IndentedTextBuilder b
var conditions = targetingRule.Conditions;

return builder.Append("IF ")
.AppendConditions(conditions, static condition => condition.GetCondition(throwIfInvalid: false))
.AppendConditions(conditions)
.AppendTargetingRuleThenPart(targetingRule, newLine: true, appendPercentageOptions: true, percentageOptionsAttribute);
}

Expand Down Expand Up @@ -287,7 +288,7 @@ public static IndentedTextBuilder AppendSetting(this IndentedTextBuilder builder

public static IndentedTextBuilder AppendSegment(this IndentedTextBuilder builder, Segment segment)
{
return builder.AppendConditions(segment.Conditions, static condition => condition);
return builder.AppendConditions(segment.Conditions);
}

public static string ToDisplayText(this Comparator comparator)
Expand Down
12 changes: 6 additions & 6 deletions src/ConfigCatClient/Evaluation/RolloutEvaluator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ private bool TryEvaluateTargetingRules(TargetingRule[] targetingRules, ref Evalu
var targetingRule = targetingRules[i];
var conditions = targetingRule.Conditions;

if (!TryEvaluateConditions(conditions, static condition => condition.GetCondition()!, targetingRule, contextSalt: context.Key, ref context, out var isMatch))
if (!TryEvaluateConditions(conditions, targetingRule, contextSalt: context.Key, ref context, out var isMatch))
{
logBuilder?
.IncreaseIndent()
Expand Down Expand Up @@ -216,8 +216,8 @@ private bool TryEvaluatePercentageOptions(PercentageOption[] percentageOptions,
throw new InvalidOperationException("Sum of percentage option percentages are less than 100).");
}

private bool TryEvaluateConditions<TCondition>(TCondition[] conditions, Func<TCondition, ICondition> getCondition, TargetingRule? targetingRule,
string contextSalt, ref EvaluateContext context, out bool result)
private bool TryEvaluateConditions<TCondition>(TCondition[] conditions, TargetingRule? targetingRule, string contextSalt, ref EvaluateContext context, out bool result)
where TCondition : IConditionProvider
{
result = true;

Expand All @@ -229,7 +229,7 @@ private bool TryEvaluateConditions<TCondition>(TCondition[] conditions, Func<TCo

for (var i = 0; i < conditions.Length; i++)
{
var condition = getCondition(conditions[i]);
var condition = conditions[i].GetCondition();

if (logBuilder is not null)
{
Expand Down Expand Up @@ -267,7 +267,7 @@ private bool TryEvaluateConditions<TCondition>(TCondition[] conditions, Func<TCo
break;

default:
throw new InvalidOperationException("Condition is missing or invalid.");
throw new InvalidOperationException(); // execution should never get here
}

if (targetingRule is null || conditions.Length > 1)
Expand Down Expand Up @@ -682,7 +682,7 @@ private bool EvaluateSegmentCondition(SegmentCondition condition, ref EvaluateCo
.IncreaseIndent()
.NewLine().Append($"Evaluating segment '{segment.Name}':");

TryEvaluateConditions(segment.Conditions, static condition => condition, targetingRule: null, contextSalt: segment.Name, ref context, out var segmentResult);
TryEvaluateConditions(segment.Conditions, targetingRule: null, contextSalt: segment.Name, ref context, out var segmentResult);

var comparator = condition.Comparator;
var result = comparator switch
Expand Down
2 changes: 1 addition & 1 deletion src/ConfigCatClient/Models/ComparisonCondition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public interface IComparisonCondition : ICondition
object ComparisonValue { get; }
}

internal sealed class ComparisonCondition : IComparisonCondition
internal sealed class ComparisonCondition : Condition, IComparisonCondition
{
public const Comparator UnknownComparator = (Comparator)byte.MaxValue;

Expand Down
55 changes: 6 additions & 49 deletions src/ConfigCatClient/Models/Condition.cs
Original file line number Diff line number Diff line change
@@ -1,59 +1,16 @@
using System;
using ConfigCat.Client.Utils;

#if USE_NEWTONSOFT_JSON
using Newtonsoft.Json;
#else
using System.Text.Json.Serialization;
#endif

namespace ConfigCat.Client;

/// <summary>
/// Base interface for conditions.
/// </summary>
public interface ICondition { }

internal struct ConditionWrapper
internal interface IConditionProvider
{
private object? condition;

#if USE_NEWTONSOFT_JSON
[JsonProperty(PropertyName = "t")]
#else
[JsonPropertyName("t")]
#endif
public ComparisonCondition? ComparisonCondition
{
readonly get => this.condition as ComparisonCondition;
set => ModelHelper.SetOneOf(ref this.condition, value);
}

#if USE_NEWTONSOFT_JSON
[JsonProperty(PropertyName = "s")]
#else
[JsonPropertyName("s")]
#endif
public SegmentCondition? SegmentCondition
{
readonly get => this.condition as SegmentCondition;
set => ModelHelper.SetOneOf(ref this.condition, value);
}

#if USE_NEWTONSOFT_JSON
[JsonProperty(PropertyName = "d")]
#else
[JsonPropertyName("d")]
#endif
public PrerequisiteFlagCondition? PrerequisiteFlagCondition
{
readonly get => this.condition as PrerequisiteFlagCondition;
set => ModelHelper.SetOneOf(ref this.condition, value);
}
Condition? GetCondition(bool throwIfInvalid = true);
}

public readonly ICondition? GetCondition(bool throwIfInvalid = true)
{
return this.condition as ICondition
?? (!throwIfInvalid ? null : throw new InvalidOperationException("Condition is missing or invalid."));
}
internal abstract class Condition : ICondition, IConditionProvider
{
public Condition? GetCondition(bool throwIfInvalid = true) => this;
}
54 changes: 54 additions & 0 deletions src/ConfigCatClient/Models/ConditionContainer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using ConfigCat.Client.Utils;

#if USE_NEWTONSOFT_JSON
using Newtonsoft.Json;
#else
using System.Text.Json.Serialization;
#endif

namespace ConfigCat.Client;

internal struct ConditionContainer : IConditionProvider
{
private object? condition;

#if USE_NEWTONSOFT_JSON
[JsonProperty(PropertyName = "t")]
#else
[JsonPropertyName("t")]
#endif
public ComparisonCondition? ComparisonCondition
{
readonly get => this.condition as ComparisonCondition;
set => ModelHelper.SetOneOf(ref this.condition, value);
}

#if USE_NEWTONSOFT_JSON
[JsonProperty(PropertyName = "s")]
#else
[JsonPropertyName("s")]
#endif
public SegmentCondition? SegmentCondition
{
readonly get => this.condition as SegmentCondition;
set => ModelHelper.SetOneOf(ref this.condition, value);
}

#if USE_NEWTONSOFT_JSON
[JsonProperty(PropertyName = "d")]
#else
[JsonPropertyName("d")]
#endif
public PrerequisiteFlagCondition? PrerequisiteFlagCondition
{
readonly get => this.condition as PrerequisiteFlagCondition;
set => ModelHelper.SetOneOf(ref this.condition, value);
}

public readonly Condition? GetCondition(bool throwIfInvalid = true)
{
return this.condition as Condition
?? (!throwIfInvalid ? null : throw new InvalidOperationException("Condition is missing or invalid."));
}
}
2 changes: 1 addition & 1 deletion src/ConfigCatClient/Models/PrerequisiteFlagCondition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public interface IPrerequisiteFlagCondition : ICondition
object ComparisonValue { get; }
}

internal sealed class PrerequisiteFlagCondition : IPrerequisiteFlagCondition
internal sealed class PrerequisiteFlagCondition : Condition, IPrerequisiteFlagCondition
{
public const PrerequisiteFlagComparator UnknownComparator = (PrerequisiteFlagComparator)byte.MaxValue;

Expand Down
2 changes: 1 addition & 1 deletion src/ConfigCatClient/Models/SegmentCondition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public interface ISegmentCondition : ICondition
SegmentComparator Comparator { get; }
}

internal sealed class SegmentCondition : ISegmentCondition
internal sealed class SegmentCondition : Condition, ISegmentCondition
{
public const SegmentComparator UnknownComparator = (SegmentComparator)byte.MaxValue;

Expand Down
6 changes: 3 additions & 3 deletions src/ConfigCatClient/Models/TargetingRule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,17 @@ public interface ITargetingRule

internal sealed class TargetingRule : ITargetingRule
{
private ConditionWrapper[]? conditions;
private ConditionContainer[]? conditions;

#if USE_NEWTONSOFT_JSON
[JsonProperty(PropertyName = "c")]
#else
[JsonPropertyName("c")]
#endif
[NotNull]
public ConditionWrapper[]? Conditions
public ConditionContainer[]? Conditions
{
get => this.conditions ?? ArrayUtils.EmptyArray<ConditionWrapper>();
get => this.conditions ?? ArrayUtils.EmptyArray<ConditionContainer>();
set => this.conditions = value;
}

Expand Down

0 comments on commit 4171dbb

Please sign in to comment.