| | | 1 | | /******************************************************************************** |
| | | 2 | | * RouteNode.cs * |
| | | 3 | | * * |
| | | 4 | | * Author: Denes Solti * |
| | | 5 | | ********************************************************************************/ |
| | | 6 | | using System; |
| | | 7 | | using System.Collections.Frozen; |
| | | 8 | | using System.Collections.Generic; |
| | | 9 | | using System.Collections.Immutable; |
| | | 10 | | |
| | | 11 | | namespace NanoRoute.Internals |
| | | 12 | | { |
| | | 13 | | /// <summary> |
| | | 14 | | /// Represents a node in the per-verb route tree. |
| | | 15 | | /// </summary> |
| | 2 | 16 | | internal sealed class RouteNode() |
| | | 17 | | { |
| | | 18 | | /// <summary> |
| | | 19 | | /// Gets the handlers registered for the current route node. |
| | | 20 | | /// </summary> |
| | 2 | 21 | | public IDictionary<HttpVerb, IList<HandlerRegistration>> HandlerRegistrations { get; } = new Dictionary<HttpVerb |
| | | 22 | | |
| | | 23 | | /// <summary> |
| | | 24 | | /// Gets the parser used by this node when it represents a parameterized segment. |
| | | 25 | | /// </summary> |
| | | 26 | | public ParameterParser? ParameterParser { get; init; } |
| | | 27 | | |
| | | 28 | | /// <summary> |
| | | 29 | | /// Gets literal child nodes keyed by case-insensitive segment value. |
| | | 30 | | /// </summary> |
| | 2 | 31 | | public IDictionary<ReadOnlyMemory<char>, RouteNode> LiteralChildren { get; } = new Dictionary<ReadOnlyMemory<cha |
| | | 32 | | |
| | | 33 | | /// <summary> |
| | | 34 | | /// Gets parser-based child nodes evaluated after literal matches. |
| | | 35 | | /// </summary> |
| | 2 | 36 | | public IList<RouteNode> ParsedChildren { get; } = new List<RouteNode>(); |
| | | 37 | | |
| | | 38 | | /// <summary> |
| | | 39 | | /// Returns true if this node is read-only. |
| | | 40 | | /// </summary> |
| | | 41 | | public bool Frozen { get; } |
| | | 42 | | |
| | 2 | 43 | | private RouteNode(RouteNode src, bool freeze): this() |
| | 2 | 44 | | { |
| | 2 | 45 | | ParameterParser = src.ParameterParser; |
| | | 46 | | |
| | 2 | 47 | | CopyCollection(src.ParsedChildren, ParsedChildren, c => c.Copy(freeze)); |
| | 2 | 48 | | CopyCollection(src.HandlerRegistrations, HandlerRegistrations, static kvp => new(kvp.Key, [.. kvp.Value])); |
| | 2 | 49 | | CopyCollection(src.LiteralChildren, LiteralChildren, kvp => new(kvp.Key, kvp.Value.Copy(freeze))); |
| | | 50 | | |
| | 2 | 51 | | if (freeze) |
| | 2 | 52 | | { |
| | 2 | 53 | | LiteralChildren = LiteralChildren.ToFrozenDictionary(ReadOnlyMemoryCharComparer.Instance); |
| | 2 | 54 | | ParsedChildren = ParsedChildren.ToImmutableArray(); |
| | 2 | 55 | | HandlerRegistrations = HandlerRegistrations.ToFrozenDictionary(static kvp => kvp.Key, static kvp => (ILi |
| | 2 | 56 | | Frozen = true; |
| | 2 | 57 | | } |
| | | 58 | | |
| | | 59 | | static void CopyCollection<TValue>(ICollection<TValue> src, ICollection<TValue> dst, Func<TValue, TValue> va |
| | | 60 | | { |
| | | 61 | | foreach (TValue item in src) |
| | | 62 | | dst.Add(valueCopy(item)); |
| | | 63 | | } |
| | 2 | 64 | | } |
| | | 65 | | |
| | | 66 | | /// <summary> |
| | | 67 | | /// Creates a deep-copy from this node. |
| | | 68 | | /// </summary> |
| | 2 | 69 | | public RouteNode Copy(bool frozen) => new(this, frozen); |
| | | 70 | | } |
| | | 71 | | } |