Skip to content

Commit

Permalink
Refactor RoutePatternFactory to trim regex dependency where possible (d…
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK authored Feb 22, 2023
1 parent 86e3a4b commit f3836ae
Showing 1 changed file with 65 additions and 56 deletions.
121 changes: 65 additions & 56 deletions src/Http/Routing/src/Patterns/RoutePatternFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public static RoutePattern Parse([StringSyntax("Route")] string pattern, object?
ArgumentNullException.ThrowIfNull(pattern);

var original = RoutePatternParser.Parse(pattern);
return PatternCore(original.RawText, Wrap(defaults), Wrap(parameterPolicies), requiredValues: null, original.PathSegments);
return PatternCore(original.RawText, Wrap(defaults), CreateRoutePatternPolicyReferences(Wrap(parameterPolicies)), requiredValues: null, original.PathSegments);
}

/// <summary>
Expand All @@ -83,7 +83,7 @@ public static RoutePattern Parse([StringSyntax("Route")] string pattern, RouteVa
ArgumentNullException.ThrowIfNull(pattern);

var original = RoutePatternParser.Parse(pattern);
return PatternCore(original.RawText, defaults, parameterPolicies, requiredValues: null, original.PathSegments);
return PatternCore(original.RawText, defaults, CreateRoutePatternPolicyReferences(parameterPolicies), requiredValues: null, original.PathSegments);
}

/// <summary>
Expand Down Expand Up @@ -112,7 +112,7 @@ public static RoutePattern Parse([StringSyntax("Route")] string pattern, object?
ArgumentNullException.ThrowIfNull(pattern);

var original = RoutePatternParser.Parse(pattern);
return PatternCore(original.RawText, Wrap(defaults), Wrap(parameterPolicies), Wrap(requiredValues), original.PathSegments);
return PatternCore(original.RawText, Wrap(defaults), CreateRoutePatternPolicyReferences(Wrap(parameterPolicies)), Wrap(requiredValues), original.PathSegments);
}

/// <summary>
Expand Down Expand Up @@ -140,7 +140,7 @@ public static RoutePattern Parse([StringSyntax("Route")] string pattern, RouteVa
ArgumentNullException.ThrowIfNull(pattern);

var original = RoutePatternParser.Parse(pattern);
return PatternCore(original.RawText, defaults, parameterPolicies, requiredValues, original.PathSegments);
return PatternCore(original.RawText, defaults, CreateRoutePatternPolicyReferences(parameterPolicies), requiredValues, original.PathSegments);
}

/// <summary>
Expand Down Expand Up @@ -193,7 +193,7 @@ public static RoutePattern Pattern(
{
ArgumentNullException.ThrowIfNull(segments);

return PatternCore(null, new RouteValueDictionary(defaults), new RouteValueDictionary(parameterPolicies), requiredValues: null, segments);
return PatternCore(null, Wrap(defaults), CreateRoutePatternPolicyReferences(Wrap(parameterPolicies)), requiredValues: null, segments);
}

/// <summary>
Expand All @@ -220,7 +220,7 @@ public static RoutePattern Pattern(
{
ArgumentNullException.ThrowIfNull(segments);

return PatternCore(null, defaults, parameterPolicies, requiredValues: null, segments);
return PatternCore(null, defaults, CreateRoutePatternPolicyReferences(parameterPolicies), requiredValues: null, segments);
}

/// <summary>
Expand Down Expand Up @@ -250,7 +250,7 @@ public static RoutePattern Pattern(
{
ArgumentNullException.ThrowIfNull(segments);

return PatternCore(rawText, new RouteValueDictionary(defaults), new RouteValueDictionary(parameterPolicies), requiredValues: null, segments);
return PatternCore(rawText, Wrap(defaults), CreateRoutePatternPolicyReferences(Wrap(parameterPolicies)), requiredValues: null, segments);
}

/// <summary>
Expand Down Expand Up @@ -279,7 +279,7 @@ public static RoutePattern Pattern(
{
ArgumentNullException.ThrowIfNull(segments);

return PatternCore(rawText, defaults, parameterPolicies, requiredValues: null, segments);
return PatternCore(rawText, defaults, CreateRoutePatternPolicyReferences(parameterPolicies), requiredValues: null, segments);
}

/// <summary>
Expand Down Expand Up @@ -332,7 +332,7 @@ public static RoutePattern Pattern(
{
ArgumentNullException.ThrowIfNull(segments);

return PatternCore(null, new RouteValueDictionary(defaults), new RouteValueDictionary(parameterPolicies), requiredValues: null, segments);
return PatternCore(null, Wrap(defaults), CreateRoutePatternPolicyReferences(Wrap(parameterPolicies)), requiredValues: null, segments);
}

/// <summary>
Expand All @@ -359,7 +359,7 @@ public static RoutePattern Pattern(
{
ArgumentNullException.ThrowIfNull(segments);

return PatternCore(null, defaults, parameterPolicies, requiredValues: null, segments);
return PatternCore(null, defaults, CreateRoutePatternPolicyReferences(parameterPolicies), requiredValues: null, segments);
}

/// <summary>
Expand Down Expand Up @@ -389,7 +389,7 @@ public static RoutePattern Pattern(
{
ArgumentNullException.ThrowIfNull(segments);

return PatternCore(rawText, new RouteValueDictionary(defaults), new RouteValueDictionary(parameterPolicies), requiredValues: null, segments);
return PatternCore(rawText, Wrap(defaults), CreateRoutePatternPolicyReferences(Wrap(parameterPolicies)), requiredValues: null, segments);
}

/// <summary>
Expand Down Expand Up @@ -418,13 +418,13 @@ public static RoutePattern Pattern(
{
ArgumentNullException.ThrowIfNull(segments);

return PatternCore(rawText, defaults, parameterPolicies, requiredValues: null, segments);
return PatternCore(rawText, defaults, CreateRoutePatternPolicyReferences(parameterPolicies), requiredValues: null, segments);
}

private static RoutePattern PatternCore(
string? rawText,
RouteValueDictionary? defaults,
RouteValueDictionary? parameterPolicies,
Dictionary<string, List<RoutePatternParameterPolicyReference>>? parameterPolicyReferences,
RouteValueDictionary? requiredValues,
IEnumerable<RoutePatternPathSegment> segments)
{
Expand All @@ -450,43 +450,6 @@ private static RoutePattern PatternCore(
}
}

Dictionary<string, List<RoutePatternParameterPolicyReference>>? updatedParameterPolicies = null;
if (parameterPolicies != null && parameterPolicies.Count > 0)
{
updatedParameterPolicies = new Dictionary<string, List<RoutePatternParameterPolicyReference>>(parameterPolicies.Count, StringComparer.OrdinalIgnoreCase);

foreach (var kvp in parameterPolicies)
{
var policyReferences = new List<RoutePatternParameterPolicyReference>();

if (kvp.Value is IParameterPolicy parameterPolicy)
{
policyReferences.Add(ParameterPolicy(parameterPolicy));
}
else if (kvp.Value is string)
{
// Constraint will convert string values into regex constraints
policyReferences.Add(Constraint(kvp.Value));
}
else if (kvp.Value is IEnumerable multiplePolicies)
{
foreach (var item in multiplePolicies)
{
// Constraint will convert string values into regex constraints
policyReferences.Add(item is IParameterPolicy p ? ParameterPolicy(p) : Constraint(item));
}
}
else
{
throw new InvalidOperationException(Resources.FormatRoutePattern_InvalidConstraintReference(
kvp.Value ?? "null",
typeof(IRouteConstraint)));
}

updatedParameterPolicies.Add(kvp.Key, policyReferences);
}
}

List<RoutePatternParameterPart>? parameters = null;
var updatedSegments = segments.ToArray();
for (var i = 0; i < updatedSegments.Length; i++)
Expand Down Expand Up @@ -554,8 +517,8 @@ private static RoutePattern PatternCore(
return new RoutePattern(
rawText,
updatedDefaults ?? EmptyDictionary,
updatedParameterPolicies != null
? updatedParameterPolicies.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList<RoutePatternParameterPolicyReference>)kvp.Value.ToArray())
parameterPolicyReferences != null
? parameterPolicyReferences.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList<RoutePatternParameterPolicyReference>)kvp.Value.ToArray())
: EmptyPoliciesDictionary,
requiredValues ?? EmptyDictionary,
(IReadOnlyList<RoutePatternParameterPart>?)parameters ?? Array.Empty<RoutePatternParameterPart>(),
Expand Down Expand Up @@ -627,16 +590,16 @@ RoutePatternPart VisitPart(RoutePatternPart part)
}

List<RoutePatternParameterPolicyReference>? parameterConstraints = null;
if ((updatedParameterPolicies == null || !updatedParameterPolicies.TryGetValue(parameter.Name, out parameterConstraints)) &&
if ((parameterPolicyReferences == null || !parameterPolicyReferences.TryGetValue(parameter.Name, out parameterConstraints)) &&
parameter.ParameterPolicies.Count > 0)
{
if (updatedParameterPolicies == null)
if (parameterPolicyReferences == null)
{
updatedParameterPolicies = new Dictionary<string, List<RoutePatternParameterPolicyReference>>(StringComparer.OrdinalIgnoreCase);
parameterPolicyReferences = new Dictionary<string, List<RoutePatternParameterPolicyReference>>(StringComparer.OrdinalIgnoreCase);
}

parameterConstraints = new List<RoutePatternParameterPolicyReference>(parameter.ParameterPolicies.Count);
updatedParameterPolicies.Add(parameter.Name, parameterConstraints);
parameterPolicyReferences.Add(parameter.Name, parameterConstraints);
}

if (parameter.ParameterPolicies.Count > 0)
Expand All @@ -661,6 +624,52 @@ RoutePatternPart VisitPart(RoutePatternPart part)
}
}

/// <summary>
/// String policy references are infered to be regex constraints. Creating them is moved here to its own method so apps can
/// trim away the regex dependency when RoutePatternFactory.Parse(string) is used. This is the method typically used by the various Map methods.
/// </summary>
private static Dictionary<string, List<RoutePatternParameterPolicyReference>>? CreateRoutePatternPolicyReferences(RouteValueDictionary? parameterPolicies)
{
Dictionary<string, List<RoutePatternParameterPolicyReference>>? updatedParameterPolicies = null;
if (parameterPolicies != null && parameterPolicies.Count > 0)
{
updatedParameterPolicies = new Dictionary<string, List<RoutePatternParameterPolicyReference>>(parameterPolicies.Count, StringComparer.OrdinalIgnoreCase);

foreach (var kvp in parameterPolicies)
{
var policyReferences = new List<RoutePatternParameterPolicyReference>();

if (kvp.Value is IParameterPolicy parameterPolicy)
{
policyReferences.Add(ParameterPolicy(parameterPolicy));
}
else if (kvp.Value is string)
{
// Constraint will convert string values into regex constraints
policyReferences.Add(Constraint(kvp.Value));
}
else if (kvp.Value is IEnumerable multiplePolicies)
{
foreach (var item in multiplePolicies)
{
// Constraint will convert string values into regex constraints
policyReferences.Add(item is IParameterPolicy p ? ParameterPolicy(p) : Constraint(item));
}
}
else
{
throw new InvalidOperationException(Resources.FormatRoutePattern_InvalidConstraintReference(
kvp.Value ?? "null",
typeof(IRouteConstraint)));
}

updatedParameterPolicies.Add(kvp.Key, policyReferences);
}
}

return updatedParameterPolicies;
}

/// <summary>
/// Creates a <see cref="RoutePatternPathSegment"/> from the provided collection
/// of parts.
Expand Down

0 comments on commit f3836ae

Please sign in to comment.