< Summary

Information
Class: NanoRoute.BuilderMetadata
Assembly: NanoRoute.dll
File(s): /home/runner/work/nanoroute/nanoroute/Src/NanoRoute/Public/BuilderMetadata.cs
Line coverage
100%
Covered lines: 26
Uncovered lines: 0
Coverable lines: 26
Total lines: 125
Line coverage: 100%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/nanoroute/nanoroute/Src/NanoRoute/Public/BuilderMetadata.cs

#LineLine coverage
 1/********************************************************************************
 2* BuilderMetadata.cs                                                            *
 3*                                                                               *
 4* Author: Denes Solti                                                           *
 5********************************************************************************/
 6using System;
 7using System.Collections.Generic;
 8using System.Linq;
 9
 10namespace NanoRoute
 11{
 12    using Internals;
 13
 14    /// <summary>
 15    /// Stores extension-defined builder settings keyed by their CLR type.
 16    /// </summary>
 17    /// <remarks>
 18    /// This type is public so third-party builder extensions can keep scoped build-time settings behind their own
 19    /// module-specific APIs. Application code usually should prefer those APIs, such as <c>ConfigureXxx()</c>
 20    /// methods, instead of reading or writing metadata directly.
 21    /// <para>
 22    /// Prefix builders receive a scoped copy of the parent metadata when they are created. Later changes made in
 23    /// either scope stay local to that scope.
 24    /// </para>
 25    /// </remarks>
 26    /// <example>
 27    /// <code>
 28    /// builder.Metadata.Set(new MyFeatureOptions { Enabled = true });
 29    ///
 30    /// MyFeatureOptions options = builder.Metadata.GetOrDefault(MyFeatureOptions.Default);
 31    /// </code>
 32    /// </example>
 33    public sealed class BuilderMetadata
 34    {
 35        private readonly Dictionary<Type, object> _items;
 36
 237        internal BuilderMetadata() => _items = [];
 38
 139        private BuilderMetadata(Dictionary<Type, object> items) => _items = items.ToDictionary
 140        (
 141            static kvp => kvp.Key,
 142            static kvp => kvp.Value is ICloneable cloneable ? cloneable.Clone() : kvp.Value
 143        );
 44
 145        internal BuilderMetadata CreateScope() => new(_items);
 46
 47        /// <summary>
 48        /// Gets the metadata value registered for <typeparamref name="T"/>, or <paramref name="defaultValue"/> when
 49        /// no value has been registered in this scope.
 50        /// </summary>
 51        /// <typeparam name="T">The metadata value type.</typeparam>
 52        /// <param name="defaultValue">The value to return when the metadata entry is absent.</param>
 53        /// <returns>The registered metadata value, or <paramref name="defaultValue"/>.</returns>
 54        /// <exception cref="ArgumentNullException">Thrown when <paramref name="defaultValue"/> is <see langword="null"/
 55        /// <example>
 56        /// <code>
 57        /// MyFeatureOptions options = builder.Metadata.GetOrDefault(MyFeatureOptions.Default);
 58        /// </code>
 59        /// </example>
 60        public T GetOrDefault<T>(T defaultValue) where T : notnull
 161        {
 162            Ensure.NotNull(defaultValue);
 63
 164            return _items.TryGetValue(typeof(T), out object? value)
 165                ? (T) value
 166                : defaultValue;
 167        }
 68
 69        /// <summary>
 70        /// Removes the metadata value registered for <typeparamref name="T"/>.
 71        /// </summary>
 72        /// <typeparam name="T">The metadata value type.</typeparam>
 73        /// <returns><see langword="true"/> when an entry was removed; otherwise <see langword="false"/>.</returns>
 74        /// <example>
 75        /// <code>
 76        /// bool removed = builder.Metadata.Remove&lt;MyFeatureOptions&gt;();
 77        /// </code>
 78        /// </example>
 179        public bool Remove<T>() where T : notnull => _items.Remove(typeof(T));
 80
 81        /// <summary>
 82        /// Registers or replaces the metadata value for <typeparamref name="T"/>.
 83        /// </summary>
 84        /// <typeparam name="T">The metadata value type.</typeparam>
 85        /// <param name="value">The metadata value.</param>
 86        /// <exception cref="ArgumentNullException">Thrown when <paramref name="value"/> is <see langword="null"/>.</exc
 87        /// <example>
 88        /// <code>
 89        /// builder.Metadata.Set(new MyFeatureOptions { Enabled = true });
 90        /// </code>
 91        /// </example>
 92        public void Set<T>(T value) where T : notnull
 193        {
 194            Ensure.NotNull(value);
 95
 196            _items[typeof(T)] = value;
 197        }
 98
 99        /// <summary>
 100        /// Tries to get the metadata value registered for <typeparamref name="T"/>.
 101        /// </summary>
 102        /// <typeparam name="T">The metadata value type.</typeparam>
 103        /// <param name="value">The registered metadata value, when one exists.</param>
 104        /// <returns><see langword="true"/> when a value exists; otherwise <see langword="false"/>.</returns>
 105        /// <example>
 106        /// <code>
 107        /// if (builder.Metadata.TryGet(out MyFeatureOptions? options))
 108        /// {
 109        ///     EnableFeature(options);
 110        /// }
 111        /// </code>
 112        /// </example>
 113        public bool TryGet<T>(out T? value) where T : notnull
 1114        {
 1115            if (_items.TryGetValue(typeof(T), out object? obj))
 1116            {
 1117                value = (T) obj;
 1118                return true;
 119            }
 120
 1121            value = default;
 1122            return false;
 1123        }
 124    }
 125}