Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
ca6682c
Removing TReturn argument from Match / MatchAsync - #6
bfren Jan 28, 2026
bdbf7d0
Adding True / False tests - #6
bfren Jan 28, 2026
b89b8a7
Moving InvalidMaybe<T> class from All - #6
bfren Jan 28, 2026
7d86b15
Adding tests for M.Match and M.MatchAsync - #6
bfren Jan 28, 2026
0df145f
Using Tests.Maybe InvalidMaybe class - #6
bfren Jan 28, 2026
e9a75ca
Generate random args in FailureGenerator - #6
bfren Jan 28, 2026
e204f35
Adding tests for Result.Failure - #6
bfren Jan 28, 2026
83abdd9
Changing nullability handling in M.Wrap, R.Wrap and Ok<T> - #6
bfren Jan 28, 2026
b3f4d85
Adding Nullable tests for Ok<T> - #6
bfren Jan 28, 2026
129d671
Using Record.Exception - #6
bfren Jan 28, 2026
b41e644
Adding further Failure and FailureValue tests - #6
bfren Jan 28, 2026
8bf470d
Adding InvalidResult class - #6
bfren Jan 28, 2026
ebc72df
Updating comments - #11
bfren Jan 29, 2026
f01c39b
Adding brief history to README - #11
bfren Jan 29, 2026
d9927db
Disallow null in new Some() - #6
bfren Jan 29, 2026
9d3170d
Adding new Some<T> tests - #6
bfren Jan 29, 2026
52d9020
Removing notnull constraint on M.Wrap - #6
bfren Jan 29, 2026
b3f7e55
Updating packages - #6
bfren Jan 29, 2026
02e5295
Using new Rnd.Intxxx functions in tests - #6
bfren Jan 29, 2026
252b6d7
Adding Maybe and Result Wrap tests - #6
bfren Jan 29, 2026
4e6fbdd
Adding 'Impl' suffix to Maybe<T>.None and Result<T>.Failure classes - #6
bfren Jan 29, 2026
a5000f0
Fixing FailValue references in comments - #10
bfren Jan 29, 2026
279ef83
Creating FailureImpl objects directly - #6
bfren Jan 29, 2026
f074cb1
Updating 'Fail' reference in README - #10
bfren Jan 29, 2026
4a70dbc
Adding NoneImpl and FailureImpl tests - #6
bfren Jan 29, 2026
f102eaf
Using Rnd.Int and Rnd.Lng shorthands - #6
bfren Jan 29, 2026
4fd7d51
Updating packages - #6
bfren Jan 29, 2026
b394ad1
Always return same None instance - #6
bfren Jan 29, 2026
f6ae71d
Adding FailureValue generator - #6
bfren Jan 29, 2026
e8f7396
Correcting nullable type in test - #6
bfren Jan 29, 2026
0bc4854
Moving extensions file to correct location - #6
bfren Jan 29, 2026
aeafb55
Moving GetEnumerator to Unsafe class - #6
bfren Jan 29, 2026
97d9f6c
Adding NoneGenerator - #6
bfren Jan 29, 2026
4a52c51
Fixing comment - #10
bfren Jan 29, 2026
9ee8361
Adding F.Format from Jeebs for formatting FailureValue strings - #6
bfren Jan 29, 2026
659aa54
Improving type name for exception types - #6
bfren Jan 29, 2026
f04254b
Adding remaining tests for Result<T> - #6
bfren Jan 29, 2026
a15fb77
Fixing test namespace - #6
bfren Jan 29, 2026
caa5d53
Testing null in ToString() - #6
bfren Jan 29, 2026
b2e9a26
Adding Maybe<T> tests - #6
bfren Jan 29, 2026
134d82b
Using discards in test functions - #6
bfren Jan 29, 2026
9ef989e
Updating packages - #6
bfren Jan 29, 2026
3f40cd4
Removing GetEnumerator from Either<> - #6
bfren Jan 29, 2026
ae92809
Merge branch 'main' into 6-improve-test-coverage
bfren Jan 29, 2026
019361d
Merge branch '6-improve-test-coverage' of https://github.com/bfren/wr…
bfren Jan 29, 2026
6233eeb
Bumping version to 1.1.0-beta.2
bfren Jan 29, 2026
5d7dbab
Disabling package validation before release of 1.1.0 - #6
bfren Jan 29, 2026
f4b62c2
Adding Result<T> True / False tests - #6
bfren Jan 29, 2026
5b9e71c
Specifying culture in ToString tests - #6
bfren Jan 29, 2026
dc00fe4
Improving F.Format tests - #6
bfren Jan 29, 2026
df259be
Bumping version to 1.1.0-beta.3
bfren Jan 29, 2026
ed03a1c
Allowing null messages in Failure.Msg - #6
bfren Jan 29, 2026
6d47e04
Updating packages
bfren Jan 29, 2026
0386c04
Adding Maybe<T> tests - #6
bfren Jan 30, 2026
6b1057a
Adding None Tests - #6
bfren Jan 30, 2026
b9fd91d
Adding additional case to Result Equals - #6
bfren Jan 30, 2026
5c9e278
Adding NumberStyles tests - #6
bfren Jan 30, 2026
565686f
Adding additional M.ParseXXX functions - #6
bfren Jan 30, 2026
dbc70e1
Adding M.None tests - #6
bfren Jan 30, 2026
759b60c
Adding M.ParseXXX tests - #6
bfren Jan 30, 2026
92c86e1
Adding IEquatable<T> to Result class - #6
bfren Jan 30, 2026
cd12b95
Adding remaining Result<T> tests - #6
bfren Jan 30, 2026
79899ba
Adding Result Match tests and improving Maybe equivalents - #6
bfren Jan 30, 2026
a127add
Adding R.Fail tests - #6
bfren Jan 30, 2026
13fc6ae
Adding R.Try tests - #6
bfren Jan 30, 2026
ea312f7
Fixing incorrect type check - #6
bfren Jan 30, 2026
6ac93c7
Ensuring Parse Date (etc) tests have a unique signature - #6
bfren Jan 30, 2026
8e025f7
Generate Failures from Exception objects - #6
bfren Jan 30, 2026
a1d4df1
Adding Failure / Exception tests - #6
bfren Jan 30, 2026
483d2ef
Adding missing Result Unwrap / Ok tests - #6
bfren Jan 30, 2026
3459ee8
Bumping version to 1.1.0-beta.4
bfren Jan 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.0.1" />
<PackageVersion Include="NSubstitute" Version="5.3.0" />
<PackageVersion Include="NSubstitute.Analyzers.CSharp" Version="1.0.17" />
<PackageVersion Include="Rnd" Version="10.1.1" />
<PackageVersion Include="Rnd" Version="10.2.0" />
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.5" />
<PackageVersion Include="xunit.v3" Version="3.2.2" />
<PackageVersion Include="xunit.v3.assert" Version="3.2.2" />
</ItemGroup>
</Project>
</Project>
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@ Various monads (including Maybe - see [here](https://en.wikipedia.org/wiki/Monad
- `Union<T>`
- `Id<T>` (support for `int`, `uint`, `long`, `ulong` and `Guid` value types)
- `Maybe<T>` (either: `Some<T>` or `None`)
- `Result<T>` (either: `Ok<T>` or `Fail`)
- `Result<T>` (either: `Ok<T>` or `Failure`)

View the [Wiki](https://github.com/bfren/wrap/wiki) for documentation.

## History

Although this library is at v1, it brings together some mature projects I have been working on since 2019. It started with a Result<T> implementation which morphed into Maybe - which reached v10 in November 2025 - and I figured it would be best to have both.

At the same time I was maintaining a StrongId library - which reached v8.5 in November 2024 - to avoid using primitives for Entity IDs. I realised the similarities between Result<T>, Maybe<T> and Id<T> and decided to bring them all together in one library: Wrap.

## Licence

> [MIT](https://mit.bfren.dev/2019)
Expand Down
2 changes: 1 addition & 1 deletion Version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.1.0-beta.1
1.1.0-beta.4
4 changes: 2 additions & 2 deletions src/All/Extensions/Maybe/MaybeExtensions.Audit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static Maybe<T> Audit<T>(this Maybe<T> @this, Action? none, Action<T>? so
{
try
{
if (@this is Maybe<T>.None && none is not null)
if (@this is Maybe<T>.NoneImpl && none is not null)
{
none();
}
Expand Down Expand Up @@ -105,7 +105,7 @@ public static async Task<Maybe<T>> AuditAsync<T>(this Task<Maybe<T>> @this, Func

try
{
if (result is Maybe<T>.None && none is not null)
if (result is Maybe<T>.NoneImpl && none is not null)
{
await none();
}
Expand Down
8 changes: 4 additions & 4 deletions src/All/Extensions/Maybe/MaybeExtensions.Bind.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,28 @@ public static partial class MaybeExtensions
/// <returns><see cref="Maybe{T}"/> object returned by <paramref name="f"/> or <see cref="None"/>.</returns>
public static Maybe<TReturn> Bind<T, TReturn>(this Maybe<T> @this, Func<T, Maybe<TReturn>> f) =>
M.Match(@this,
none: M.None,
none: () => M.None,
some: f
);

/// <inheritdoc cref="Bind{T, TReturn}(Maybe{T}, Func{T, Maybe{TReturn}})"/>
public static Task<Maybe<TReturn>> BindAsync<T, TReturn>(this Maybe<T> @this, Func<T, Task<Maybe<TReturn>>> f) =>
M.MatchAsync(@this,
none: M.None,
none: () => M.None,
some: f
);

/// <inheritdoc cref="Bind{T, TReturn}(Maybe{T}, Func{T, Maybe{TReturn}})"/>
public static Task<Maybe<TReturn>> BindAsync<T, TReturn>(this Task<Maybe<T>> @this, Func<T, Maybe<TReturn>> f) =>
M.MatchAsync(@this,
none: M.None,
none: () => M.None,
some: f
);

/// <inheritdoc cref="Bind{T, TReturn}(Maybe{T}, Func{T, Maybe{TReturn}})"/>
public static Task<Maybe<TReturn>> BindAsync<T, TReturn>(this Task<Maybe<T>> @this, Func<T, Task<Maybe<TReturn>>> f) =>
M.MatchAsync(@this,
none: M.None,
none: () => M.None,
some: f
);
}
8 changes: 4 additions & 4 deletions src/All/Extensions/Maybe/MaybeExtensions.IsFalse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ public static partial class MaybeExtensions
/// <returns>Whether or not the value of <paramref name="this"/> is <see langword="false"/>.</returns>
public static bool IsFalse(this Maybe<bool> @this) =>
M.Match(@this,
none: false,
some: x => x == false
none: () => false,
some: x => !x
);

/// <inheritdoc cref="IsTrue(Maybe{bool})"/>
public static Task<bool> IsFalseAsync(this Task<Maybe<bool>> @this) =>
M.MatchAsync(@this,
none: false,
some: x => x == false
none: () => false,
some: x => !x
);
}
4 changes: 2 additions & 2 deletions src/All/Extensions/Maybe/MaybeExtensions.IsTrue.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ public static partial class MaybeExtensions
/// <returns>Whether or not the value of <paramref name="this"/> is <see langword="true"/>.</returns>
public static bool IsTrue(this Maybe<bool> @this) =>
M.Match(@this,
none: false,
none: () => false,
some: x => x
);

/// <inheritdoc cref="IsTrue(Maybe{bool})"/>
public static Task<bool> IsTrueAsync(this Task<Maybe<bool>> @this) =>
M.MatchAsync(@this,
none: false,
none: () => false,
some: x => x
);
}
8 changes: 4 additions & 4 deletions src/All/Extensions/Maybe/MaybeExtensions.Map.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,28 +25,28 @@ public static partial class MaybeExtensions
/// <returns><see cref="Some{T}"/> object or <see cref="None"/>.</returns>
public static Maybe<TReturn> Map<T, TReturn>(this Maybe<T> @this, Func<T, TReturn> f) =>
M.Match(@this,
none: M.None,
none: () => M.None,
some: x => M.Wrap(f(x))
);

/// <inheritdoc cref="Map{T, TReturn}(Maybe{T}, Func{T, TReturn})"/>
public static Task<Maybe<TReturn>> MapAsync<T, TReturn>(this Maybe<T> @this, Func<T, Task<TReturn>> f) =>
M.MatchAsync(@this,
none: M.None,
none: () => M.None,
some: async x => M.Wrap(await f(x))
);

/// <inheritdoc cref="Map{T, TReturn}(Maybe{T}, Func{T, TReturn})"/>
public static Task<Maybe<TReturn>> MapAsync<T, TReturn>(this Task<Maybe<T>> @this, Func<T, TReturn> f) =>
M.MatchAsync(@this,
none: M.None,
none: () => M.None,
some: x => M.Wrap(f(x))
);

/// <inheritdoc cref="Map{T, TReturn}(Maybe{T}, Func{T, TReturn})"/>
public static Task<Maybe<TReturn>> MapAsync<T, TReturn>(this Task<Maybe<T>> @this, Func<T, Task<TReturn>> f) =>
M.MatchAsync(@this,
none: M.None,
none: () => M.None,
some: async x => M.Wrap(await f(x))
);
}
16 changes: 0 additions & 16 deletions src/All/Extensions/Maybe/MaybeExtensions.Match.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,10 @@ public static Task MatchAsync<T>(this Maybe<T> @this, Func<Task> none, Func<T, T
public static Task MatchAsync<T>(this Task<Maybe<T>> @this, Func<Task> none, Func<T, Task> some) =>
M.MatchAsync(@this, none, some);

/// <inheritdoc cref="M.Match{T, TReturn}(Maybe{T}, Func{TReturn}, Func{T, TReturn})"/>
public static TReturn Match<T, TReturn>(this Maybe<T> @this, TReturn none, Func<T, TReturn> some) =>
M.Match(@this, none, some);

/// <inheritdoc cref="M.Match{T, TReturn}(Maybe{T}, Func{TReturn}, Func{T, TReturn})"/>
public static TReturn Match<T, TReturn>(this Maybe<T> @this, Func<TReturn> none, Func<T, TReturn> some) =>
M.Match(@this, none, some);

/// <inheritdoc cref="M.Match{T, TReturn}(Maybe{T}, Func{TReturn}, Func{T, TReturn})"/>
public static Task<TReturn> MatchAsync<T, TReturn>(this Maybe<T> @this, TReturn none, Func<T, Task<TReturn>> some) =>
M.MatchAsync(@this, none, some);

/// <inheritdoc cref="M.Match{T, TReturn}(Maybe{T}, Func{TReturn}, Func{T, TReturn})"/>
public static Task<TReturn> MatchAsync<T, TReturn>(this Maybe<T> @this, Func<TReturn> none, Func<T, Task<TReturn>> some) =>
M.MatchAsync(@this, none, some);
Expand All @@ -52,14 +44,6 @@ public static Task<TReturn> MatchAsync<T, TReturn>(this Maybe<T> @this, Func<Tas
public static Task<TReturn> MatchAsync<T, TReturn>(this Maybe<T> @this, Func<Task<TReturn>> none, Func<T, Task<TReturn>> some) =>
M.MatchAsync(@this, none, some);

/// <inheritdoc cref="M.Match{T, TReturn}(Maybe{T}, Func{TReturn}, Func{T, TReturn})"/>
public static Task<TReturn> MatchAsync<T, TReturn>(this Task<Maybe<T>> @this, TReturn none, Func<T, TReturn> some) =>
M.MatchAsync(@this, none, some);

/// <inheritdoc cref="M.Match{T, TReturn}(Maybe{T}, Func{TReturn}, Func{T, TReturn})"/>
public static Task<TReturn> MatchAsync<T, TReturn>(this Task<Maybe<T>> @this, TReturn none, Func<T, Task<TReturn>> some) =>
M.MatchAsync(@this, none, some);

/// <inheritdoc cref="M.Match{T, TReturn}(Maybe{T}, Func{TReturn}, Func{T, TReturn})"/>
public static Task<TReturn> MatchAsync<T, TReturn>(this Task<Maybe<T>> @this, Func<TReturn> none, Func<T, TReturn> some) =>
M.MatchAsync(@this, none, some);
Expand Down
2 changes: 1 addition & 1 deletion src/All/Extensions/Maybe/MaybeExtensions.MatchIf.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public static TReturn MatchIf<T, TReturn>(this Maybe<T> @this,
Func<T, TReturn> someTrue
) =>
Match(@this,
none: none(),
none: none,
some: x => predicate(x) switch
{
false =>
Expand Down
4 changes: 2 additions & 2 deletions src/All/Extensions/Result/ResultExtensions.Audit.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public static Result<T> Audit<T>(this Result<T> @this, Action<FailureValue>? fai
{
try
{
if (@this is Result<T>.Failure y && fail is not null)
if (@this is Result<T>.FailureImpl y && fail is not null)
{
fail(y.Value);
}
Expand Down Expand Up @@ -111,7 +111,7 @@ public static async Task<Result<T>> AuditAsync<T>(this Task<Result<T>> @this, Fu

try
{
if (result is Result<T>.Failure y && fail is not null)
if (result is Result<T>.FailureImpl y && fail is not null)
{
await fail(y.Value);
}
Expand Down
2 changes: 1 addition & 1 deletion src/All/Extensions/Unsafe/UnsafeExtensions.TryFailure.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static partial class UnsafeExtensions
/// <returns>True if <paramref name="this"/> contains a <see cref="Failure"/>.</returns>
public static bool TryFailure<T>(this Unsafe<Result<T>, FailureValue, T> @this, out FailureValue value)
{
if (@this.Value is Result<T>.Failure failure)
if (@this.Value is Result<T>.FailureImpl failure)
{
value = failure.Value;
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,28 +34,28 @@ public static partial class MaybeToMaybeExtensions
/// <param name="g">Return map function.</param>
public static Maybe<TReturn> SelectMany<T, TInner, TReturn>(this Maybe<T> @this, Func<T, Maybe<TInner>> f, Func<T, TInner, TReturn> g) =>
M.Match(@this,
none: M.None,
none: () => M.None,
some: x => f(x).Map(y => g(x, y))
);

/// <inheritdoc cref="SelectMany{T, TInner, TReturn}(Maybe{T}, Func{T, Maybe{TInner}}, Func{T, TInner, TReturn})"/>
public static Task<Maybe<TReturn>> SelectMany<T, TInner, TReturn>(this Maybe<T> @this, Func<T, Task<Maybe<TInner>>> f, Func<T, TInner, TReturn> g) =>
M.MatchAsync(@this,
none: M.None,
none: () => M.None,
some: x => f(x).MapAsync(y => g(x, y))
);

/// <inheritdoc cref="SelectMany{T, TInner, TReturn}(Maybe{T}, Func{T, Maybe{TInner}}, Func{T, TInner, TReturn})"/>
public static Task<Maybe<TReturn>> SelectMany<T, TInner, TReturn>(this Task<Maybe<T>> @this, Func<T, Maybe<TInner>> f, Func<T, TInner, TReturn> g) =>
M.MatchAsync(@this,
none: M.None,
none: () => M.None,
some: x => f(x).Map(y => g(x, y))
);

/// <inheritdoc cref="SelectMany{T, TInner, TReturn}(Maybe{T}, Func{T, Maybe{TInner}}, Func{T, TInner, TReturn})"/>
public static Task<Maybe<TReturn>> SelectMany<T, TInner, TReturn>(this Task<Maybe<T>> @this, Func<T, Task<Maybe<TInner>>> f, Func<T, TInner, TReturn> g) =>
M.MatchAsync(@this,
none: M.None,
none: () => M.None,
some: x => f(x).MapAsync(y => g(x, y))
);
}
108 changes: 108 additions & 0 deletions src/Common/Functions/F.Format.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Wrap: .NET monads.
// Copyright (c) bfren - licensed under https://mit.bfren.dev/2019

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;

namespace Wrap;

public static partial class F
{
/// <inheritdoc cref="Format{T}(string, T, string?)"/>
public static string Format<T>(string formatString, T source) =>
Format(formatString, source, null);

/// <summary>
/// Works like string.Format() but with named as well as numbered placeholders.
/// <para>Source is Array: values will be inserted in order (regardless of placeholder values).</para>
/// <para>Source is Object: property names must match placeholders or they will be left in place.</para>
/// </summary>
/// <remarks>
/// Inspired by http://james.newtonking.com/archive/2008/03/29/formatwith-2-0-string-formatting-with-named-variables,
/// (significantly) altered to work without requiring DataBinder.
/// </remarks>
/// <typeparam name="T">Source type.</typeparam>
/// <param name="formatString">String to format.</param>
/// <param name="source">Source object to use for template values.</param>
/// <param name="replaceIfNullOrEmpty">Returned if <paramref name="formatString"/> or <paramref name="source"/> are null / empty.</param>
/// <returns>Formatted string.</returns>
public static string Format<T>(string formatString, T source, string? replaceIfNullOrEmpty)
{
// Return if format string is null or empty
if (string.IsNullOrWhiteSpace(formatString))
{
return replaceIfNullOrEmpty ?? string.Empty;
}

// Return if source is null or an empty array
if (source is null)
{
return replaceIfNullOrEmpty ?? formatString;
}
else if (source is Array arr && arr.Length == 0)
{
return replaceIfNullOrEmpty ?? formatString;
}

// Thanks James Newton-King!
var regex = TemplateMatcherRegex();

var values = new List<object>();
var replaceIndex = 0; // keeps track of replace loop so we can match named template values with an array source
var numberedTemplates = true;
var rewrittenFormat = regex.Replace(formatString, (m) =>
{
var startGroup = m.Groups["start"];
var templateGroup = m.Groups["template"];
var formatGroup = m.Groups["format"];
var endGroup = m.Groups["end"];

// This is the value inside the braces, e.g. "0" in "{0}" or "A" in "{A}"
// Remove any @ symbols from the start - used by Serilog to denote an object format
// but breaks the following
var template = templateGroup.Value.TrimStart('@');
var templateIsNumber = int.TryParse(template, out var templateNumber);
numberedTemplates = numberedTemplates && templateIsNumber;

// Switch on the source type, using variety of methods to get this template's value
var flags = BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance;
var value = source switch
{
// Source array - get specific item in array
Array arr when numberedTemplates && templateNumber < arr.Length && arr.GetValue(templateNumber) is object val =>
val,

// Source array - get next item in array
Array arr when replaceIndex < arr.Length && arr.GetValue(replaceIndex++) is object val =>
val,

// Source object - get matching property value
{ } obj when typeof(T).GetProperty(template, flags)?.GetValue(obj) is object val =>
val,

// Nothing matches to use
_ =>
$"{{{template}}}"
};

values.Add(value);

// Recreate format using zero-based string
return new string('{', startGroup.Captures.Count)
+ (values.Count - 1)
+ formatGroup.Value
+ new string('}', endGroup.Captures.Count);
});

// Format string
var formatted = string.Format(DefaultCulture, rewrittenFormat, [.. values]);

// If the string still contains any templates, return original format string
return regex.IsMatch(formatted) ? formatString : formatted;
}

[GeneratedRegex("(?<start>\\{)+(?<template>[\\w\\.\\[\\]@]+)(?<format>:[^}]+)?(?<end>\\})+", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant)]
private static partial Regex TemplateMatcherRegex();
}
18 changes: 0 additions & 18 deletions src/Common/IEither.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Copyright (c) bfren - licensed under https://mit.bfren.dev/2019

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Wrap;
Expand All @@ -23,23 +22,6 @@ public interface IEither<TLeft, TRight>
/// the object is <typeparamref name="TLeft"/>.</param>
/// <returns>Value of object or provided by <paramref name="getValue"/>.</returns>
TRight Unwrap(Func<TLeft, TRight> getValue);

/// <summary>
/// Use enumerator pattern to get <typeparamref name="TRight"/> value.
/// </summary>
/// <remarks>
/// <para>
/// For example:
/// </para>
/// <code>
/// foreach (var right in either) {
/// // if 'either' is <typeparamref name="TLeft"/>, the loop is empty
/// // otherwise 'right' is <typeparamref name="TRight"/><br/>
/// }
/// </code>
/// </remarks>
/// <returns>Enumerator containing one value if this is <typeparamref name="TRight"/>.</returns>
IEnumerator<TRight> GetEnumerator();
}

/// <summary>
Expand Down
Loading