Skip to content

Commit 51344fe

Browse files
authored
Merge pull request #599 from yringler/545-add-extensions
Add extensions: Bind optional, ensure not, map, optional, required
2 parents 04c4220 + 957ef76 commit 51344fe

File tree

6 files changed

+131
-0
lines changed

6 files changed

+131
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
using System;
2+
3+
namespace CSharpFunctionalExtensions
4+
{
5+
public static partial class MaybeExtensions
6+
{
7+
/// <summary>
8+
/// Convert an optional value into a Result. The result, being optional, is of type Maybe.
9+
/// </summary>
10+
public static Result<Maybe<TOut>, TError> BindOptional<TIn, TOut, TError>(
11+
this Maybe<TIn> maybe,
12+
Func<TIn, Result<TOut, TError>> bind)
13+
{
14+
return maybe.Bind(v => Maybe.From(bind(v))).Optional();
15+
}
16+
}
17+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
namespace CSharpFunctionalExtensions
2+
{
3+
public static partial class MaybeExtensions
4+
{
5+
/// <summary>
6+
/// Mark the possibly null value as optional. Null is not an error, it's just null.
7+
/// </summary>
8+
public static Result<Maybe<T>, E> Optional<T, E>(this Maybe<Result<T, E>> maybe)
9+
{
10+
if (maybe.HasNoValue)
11+
return Result.Success<Maybe<T>, E>(Maybe<T>.None);
12+
13+
if (maybe.Value.IsFailure)
14+
return Result.Failure<Maybe<T>, E>(maybe.Value.Error);
15+
16+
return Result.Success<Maybe<T>, E>(Maybe.From(maybe.Value.Value));
17+
}
18+
19+
/// <summary>
20+
/// Mark the possibly null value as optional. Null is not an error, it's just null.
21+
/// </summary>
22+
public static Result<Maybe<T>> Optional<T>(this Maybe<Result<T>> maybe)
23+
{
24+
if (maybe.HasNoValue)
25+
return Result.Success<Maybe<T>>(Maybe<T>.None);
26+
27+
if (maybe.Value.IsFailure)
28+
return Result.Failure<Maybe<T>>(maybe.Value.Error);
29+
30+
return Result.Success<Maybe<T>>(Maybe.From(maybe.Value.Value));
31+
}
32+
}
33+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System;
2+
3+
namespace CSharpFunctionalExtensions
4+
{
5+
public static partial class ResultExtensions
6+
{
7+
/// <summary>
8+
/// Change from one result type to another, while staying optional (the return type still contains <see cref="Maybe"/>)
9+
/// Even though it's a Result&lt;Maybe&gt;, the mapping function only has to
10+
/// operate on the innermost value, and is only called if it's present.
11+
/// </summary>
12+
public static Result<Maybe<K>, E> BindOptional<T, K, E>(
13+
this Result<Maybe<T>, E> result,
14+
Func<T, Result<K, E>> bind)
15+
{
16+
if (result.IsFailure)
17+
return Result.Failure<Maybe<K>, E>(result.Error);
18+
19+
if (result.Value.HasNoValue)
20+
return Result.Success<Maybe<K>, E>(Maybe.None);
21+
22+
return bind(result.Value.Value).Map(Maybe.From);
23+
}
24+
}
25+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using System;
2+
3+
namespace CSharpFunctionalExtensions
4+
{
5+
public static partial class ResultExtensions
6+
{
7+
/// <summary>
8+
/// Returns a new failure result if the predicate is true. Otherwise returns the starting result.
9+
/// </summary>
10+
public static Result<T> EnsureNot<T>(this Result<T> result, Func<T, bool> test, string error) =>
11+
result.Ensure(v => !test(v), error);
12+
13+
/// <summary>
14+
/// Returns a new failure result if the predicate is true. Otherwise returns the starting result.
15+
/// </summary>
16+
public static Result<T, E> EnsureNot<T, E>(this Result<T, E> result, Func<T, bool> test, E error) =>
17+
result.Ensure(v => !test(v), error);
18+
}
19+
}

CSharpFunctionalExtensions/Result/Methods/Extensions/Map.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,5 +107,25 @@ TContext context
107107

108108
return Result.Success(func(context));
109109
}
110+
111+
public static Result<Maybe<K>> Map<T, K>(
112+
this Result<Maybe<T>> result,
113+
Func<T, K> func)
114+
{
115+
if (result.IsFailure)
116+
return Result.Failure<Maybe<K>>(result.Error);
117+
118+
return Result.Success<Maybe<K>>(result.Value.Map(func));
119+
}
120+
121+
public static Result<Maybe<K>, E> Map<T, K, E>(
122+
this Result<Maybe<T>, E> result,
123+
Func<T, K> func)
124+
{
125+
if (result.IsFailure)
126+
return Result.Failure<Maybe<K>, E>(result.Error);
127+
128+
return Result.Success<Maybe<K>, E>(result.Value.Map(func));
129+
}
110130
}
111131
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
namespace CSharpFunctionalExtensions
2+
{
3+
public static partial class ResultExtensions
4+
{
5+
/// <summary>
6+
/// The optional value is required, so convert to a failed result if there's no value.
7+
/// </summary>
8+
public static Result<T, E> Required<T, E>(this Result<Maybe<T>, E> result, E error) =>
9+
result.Bind(value => value.ToResult(error));
10+
11+
/// <summary>
12+
/// The optional value is required, so convert to a failed result if there's no value.
13+
/// </summary>
14+
public static Result<T> Required<T>(this Result<Maybe<T>> result, string error) =>
15+
result.Bind(value => value.ToResult(error));
16+
}
17+
}

0 commit comments

Comments
 (0)