-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Support Downcast on the Monadic Types (Option, Either, Result)
* with tests
- Loading branch information
1 parent
dac97a4
commit d0e1802
Showing
3 changed files
with
117 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
namespace Funcky.Test; | ||
|
||
public sealed class DownCastTest | ||
{ | ||
[Fact] | ||
public void DownCastToObjectOfRuntimeTypeReturnsSomeOfTheRequestedType() | ||
{ | ||
var option = Option.Some<object>("Hello world!"); | ||
|
||
FunctionalAssert.Some("Hello world!", DownCast<string>.From(option)); | ||
} | ||
|
||
[Fact] | ||
public void DownCastToWrongObjectOfRuntimeTypeReturnsNone() | ||
{ | ||
var option = Option.Some(new object()); | ||
|
||
FunctionalAssert.None(DownCast<string>.From(option)); | ||
} | ||
|
||
[Fact] | ||
public void DownCastFromANoneAlwaysGivesNone() | ||
{ | ||
var option = Option<object>.None; | ||
|
||
FunctionalAssert.None(DownCast<string>.From(option)); | ||
} | ||
|
||
[Fact] | ||
public void DownCastToObjectOfRuntimeTypeReturnsRightOfTheRequestedType() | ||
{ | ||
var either = Either<string, object>.Right("Hello world!"); | ||
|
||
FunctionalAssert.Right("Hello world!", DownCast<string>.From(either, () => "failed cast!")); | ||
} | ||
|
||
[Fact] | ||
public void DownCastToWrongObjectOfRuntimeTypeReturnsLeft() | ||
{ | ||
var either = Either<string, object>.Right(new object()); | ||
|
||
FunctionalAssert.Left("failed cast!", DownCast<string>.From(either, () => "failed cast!")); | ||
} | ||
|
||
[Fact] | ||
public void DownCastFromALeftAlwaysGivesTheOldLeft() | ||
{ | ||
var either = Either<string, object>.Left("initial left state!"); | ||
|
||
FunctionalAssert.Left("initial left state!", DownCast<string>.From(either, () => "failed cast!")); | ||
} | ||
|
||
[Fact] | ||
public void DownCastToObjectOfRuntimeTypeReturnsOkOfTheRequestedType() | ||
{ | ||
var result = Result.Ok<object>("Hello world!"); | ||
|
||
FunctionalAssert.Ok("Hello world!", DownCast<string>.From(result)); | ||
} | ||
|
||
[Fact] | ||
public void DownCastToWrongObjectOfRuntimeTypeReturnsError() | ||
{ | ||
var result = Result.Ok(new object()); | ||
|
||
var exception = FunctionalAssert.Error(DownCast<string>.From(result)); | ||
Assert.IsType<InvalidCastException>(exception); | ||
} | ||
|
||
[Fact] | ||
public void DownCastFromAnErrorAlwaysGivesTheOldError() | ||
{ | ||
var result = Result<object>.Error(new FileNotFoundException()); | ||
|
||
var exception = FunctionalAssert.Error(DownCast<string>.From(result)); | ||
Assert.IsType<FileNotFoundException>(exception); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
namespace Funcky; | ||
|
||
public static class DownCast<TResult> | ||
where TResult : class | ||
{ | ||
public static Option<TResult> From<TItem>(Option<TItem> option) | ||
where TItem : class | ||
=> option.SelectMany(OptionDownCast); | ||
|
||
public static Result<TResult> From<TItem>(Result<TItem> result) | ||
where TItem : class | ||
=> result.SelectMany(ResultDownCast); | ||
|
||
public static Either<TLeft, TResult> From<TLeft, TRight>(Either<TLeft, TRight> either, Func<TLeft> failedCast) | ||
where TRight : class | ||
where TLeft : notnull | ||
=> either.SelectMany(right => EitherDownCast(failedCast, right)); | ||
|
||
private static Option<TResult> OptionDownCast<TItem>(TItem item) | ||
where TItem : class | ||
=> Option.FromNullable(item as TResult); | ||
|
||
private static Result<TResult> ResultDownCast<TValidResult>(TValidResult result) | ||
where TValidResult : class | ||
=> result as TResult is { } validResult | ||
? Result.Ok(validResult) | ||
: Result<TResult>.Error(new InvalidCastException()); | ||
|
||
private static Either<TLeft, TResult> EitherDownCast<TLeft, TRight>(Func<TLeft> failedCast, TRight right) | ||
where TRight : class | ||
where TLeft : notnull | ||
=> right as TResult is { } result | ||
? Either<TLeft, TResult>.Right(result) | ||
: Either<TLeft, TResult>.Left(failedCast()); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
#nullable enable | ||
|
||
Funcky.DownCast<TResult> | ||
static Funcky.DownCast<TResult>.From<TItem>(Funcky.Monads.Option<TItem!> option) -> Funcky.Monads.Option<TResult!> | ||
static Funcky.DownCast<TResult>.From<TItem>(Funcky.Monads.Result<TItem!> result) -> Funcky.Monads.Result<TResult!> | ||
static Funcky.DownCast<TResult>.From<TLeft, TRight>(Funcky.Monads.Either<TLeft, TRight!> either, System.Func<TLeft>! failedCast) -> Funcky.Monads.Either<TLeft, TResult!> |