|
| 1 | +// Copyright (c) Tenacom and contributors. Licensed under the MIT license. |
| 2 | +// See the LICENSE file in the project root for full license information. |
| 3 | + |
| 4 | +#if NET6_0_OR_GREATER |
| 5 | + |
| 6 | +using System; |
| 7 | +using System.Runtime.CompilerServices; |
| 8 | +using System.Text; |
| 9 | + |
| 10 | +namespace Louis.Text; |
| 11 | + |
| 12 | +#pragma warning disable CA1815 // Override equals and operator equals on value types - They would never be used anyway |
| 13 | +#pragma warning disable RS0027 // API with optional parameter(s) should have the most parameters amongst its public overloads - Just mimicking StringBuilder.AppendInterpolatedStringHandler's APIs here. |
| 14 | + |
| 15 | +/// <summary> |
| 16 | +/// <para>Provides an interpolated string handler that only performs formatting if a given condition is <see langword="false"/>.</para> |
| 17 | +/// <para>This type is only available on .NET 6.0 and greater.</para> |
| 18 | +/// <para>This type is only meant to be used by compiler-generated code. As such, it performs no parameter validation whatsoever.</para> |
| 19 | +/// <example> |
| 20 | +/// <para>The following code shows how this type can be used as an interpolated string handler:</para> |
| 21 | +/// <code> |
| 22 | +/// using System; |
| 23 | +/// using System.Runtime.CompilerServices; |
| 24 | +/// |
| 25 | +/// public static class ConsoleUtility |
| 26 | +/// { |
| 27 | +/// // Write a message to the console only if condition is false. |
| 28 | +/// // Usage example: ConsoleUtility.WriteLineUnless(myVar > 0, $"{nameof(myVar)} is {myVar} but should be greater than zero."); |
| 29 | +/// // String interpolation will only take place if necessary. |
| 30 | +/// public static void WriteLineUnless(bool condition, [InterpolatedStringHandlerArgument(nameof(condition))] ref FalseConditionInterpolatedStringHandler message) |
| 31 | +/// { |
| 32 | +/// if (!condition) |
| 33 | +/// { |
| 34 | +/// Console.WriteLine(message.ToStringAndClear()); |
| 35 | +/// } |
| 36 | +/// } |
| 37 | +/// } |
| 38 | +/// </code> |
| 39 | +/// </example> |
| 40 | +/// </summary> |
| 41 | +[InterpolatedStringHandler] |
| 42 | +public struct FalseConditionInterpolatedStringHandler |
| 43 | +{ |
| 44 | + private StringBuilder? _builder; |
| 45 | + private StringBuilder.AppendInterpolatedStringHandler _handler; |
| 46 | + |
| 47 | + /// <summary> |
| 48 | + /// Initializes a new instance of the <see cref="FalseConditionInterpolatedStringHandler"/> struct. |
| 49 | + /// </summary> |
| 50 | + /// <param name="literalLength">The number of constant characters outside of interpolation expressions in the interpolated string.</param> |
| 51 | + /// <param name="formattedCount">The number of interpolation expressions in the interpolated string.</param> |
| 52 | + /// <param name="condition">The condition that determines whether formatting will actually take place.</param> |
| 53 | + /// <param name="shouldAppend">A value indicating whether formatting should proceed.</param> |
| 54 | + /// <remarks> |
| 55 | + /// <para>This constructor is only intended to be called by compiler-generated code. |
| 56 | + /// As such, it doesn't perform argument validation.</para> |
| 57 | + /// </remarks> |
| 58 | + public FalseConditionInterpolatedStringHandler(int literalLength, int formattedCount, bool condition, out bool shouldAppend) |
| 59 | + { |
| 60 | + shouldAppend = !condition; |
| 61 | + if (shouldAppend) |
| 62 | + { |
| 63 | + var builder = new StringBuilder(); |
| 64 | + _handler = new(literalLength, formattedCount, builder); |
| 65 | + _builder = builder; |
| 66 | + } |
| 67 | + } |
| 68 | + |
| 69 | + /// <summary> |
| 70 | + /// Extracts the built string and frees any allocated memory. |
| 71 | + /// </summary> |
| 72 | + /// <returns>The built string.</returns> |
| 73 | + public string ToStringAndClear() |
| 74 | + { |
| 75 | + if (_builder is null) |
| 76 | + { |
| 77 | + return string.Empty; |
| 78 | + } |
| 79 | + |
| 80 | + var message = _builder.ToString(); |
| 81 | + this = default; |
| 82 | + return message; |
| 83 | + } |
| 84 | + |
| 85 | + /// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendLiteral(string)"/> |
| 86 | + public void AppendLiteral(string value) => _handler.AppendLiteral(value); |
| 87 | + |
| 88 | + /// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted{T}(T)"/> |
| 89 | + public void AppendFormatted<T>(T value) => _handler.AppendFormatted(value); |
| 90 | + |
| 91 | + /// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted{T}(T, string?)"/> |
| 92 | + public void AppendFormatted<T>(T value, string? format) => _handler.AppendFormatted(value, format); |
| 93 | + |
| 94 | + /// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted{T}(T, int)"/> |
| 95 | + public void AppendFormatted<T>(T value, int alignment) => _handler.AppendFormatted(value, alignment); |
| 96 | + |
| 97 | + /// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted{T}(T, int, string?)"/> |
| 98 | + public void AppendFormatted<T>(T value, int alignment, string? format) => _handler.AppendFormatted(value, alignment, format); |
| 99 | + |
| 100 | + /// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(ReadOnlySpan{char})"/> |
| 101 | + public void AppendFormatted(ReadOnlySpan<char> value) => _handler.AppendFormatted(value); |
| 102 | + |
| 103 | + /// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(ReadOnlySpan{char}, int, string?)"/> |
| 104 | + public void AppendFormatted(ReadOnlySpan<char> value, int alignment = 0, string? format = null) => _handler.AppendFormatted(value, alignment, format); |
| 105 | + |
| 106 | + /// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(string?)"/> |
| 107 | + public void AppendFormatted(string? value) => _handler.AppendFormatted(value); |
| 108 | + |
| 109 | + /// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(string?, int, string?)"/> |
| 110 | + public void AppendFormatted(string? value, int alignment = 0, string? format = null) => _handler.AppendFormatted(value, alignment, format); |
| 111 | + |
| 112 | + /// <inheritdoc cref="StringBuilder.AppendInterpolatedStringHandler.AppendFormatted(object?, int, string?)"/> |
| 113 | + public void AppendFormatted(object? value, int alignment = 0, string? format = null) => _handler.AppendFormatted(value, alignment, format); |
| 114 | +} |
| 115 | + |
| 116 | +#endif |
0 commit comments