Skip to content

Commit

Permalink
Fix missing overloads for SelectMany with Task (#144)
Browse files Browse the repository at this point in the history
Fix #145
  • Loading branch information
Galad committed May 31, 2019
1 parent 08a92b6 commit 8c629dd
Show file tree
Hide file tree
Showing 18 changed files with 593 additions and 512 deletions.
120 changes: 102 additions & 18 deletions src/Tranquire/ActionExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Threading.Tasks;
using Tranquire.Extensions;
using SM = Tranquire.Extensions.SelectMany;

namespace Tranquire
{
Expand Down Expand Up @@ -111,77 +112,160 @@ public DiscardActionResult(IAction<TResult> action)
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="action">The action which result is transformed</param>
/// <param name="source">The action which result is transformed</param>
/// <param name="selector">A transform function that returns a new action.</param>
/// <returns></returns>
public static IAction<TResult> SelectMany<TSource, TResult>(this IAction<TSource> action, Func<TSource, IAction<TResult>> selector)
public static IAction<TResult> SelectMany<TSource, TResult>(this IAction<TSource> source, Func<TSource, IAction<TResult>> selector)
{
return new SelectManyAction<TSource, TResult>(action, selector);
var selectMany = SM.Create(source, SM.Execute<TSource>(), selector, SM.Execute<TResult>());
return selectMany.ToAction();
}

/// <summary>
/// Projects the result of an action into a new question.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="action">The action which result is transformed</param>
/// <param name="source">The action which result is transformed</param>
/// <param name="selector">A transform function that returns a new action.</param>
/// <returns></returns>
public static IQuestion<TResult> SelectMany<TSource, TResult>(this IAction<TSource> action, Func<TSource, IQuestion<TResult>> selector)
public static IQuestion<TResult> SelectMany<TSource, TResult>(this IAction<TSource> source, Func<TSource, IQuestion<TResult>> selector)
{
return new SelectManyActionToQuestion<TSource, TResult>(action, selector);
var selectMany = SM.Create(source, SM.Execute<TSource>(), selector, SM.AsksFor<TResult>());
return selectMany.ToQuestion();
}

/// <summary>
/// Projects the result of an asynchronous action into a new action.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="action">The action which result is transformed</param>
/// <param name="source">The action which result is transformed</param>
/// <param name="selector">A transform function that returns a new action.</param>
/// <returns></returns>
public static IAction<Task<TResult>> SelectMany<TSource, TResult>(this IAction<Task<TSource>> action, Func<TSource, IAction<TResult>> selector)
public static IAction<Task<TResult>> SelectMany<TSource, TResult>(this IAction<Task<TSource>> source, Func<TSource, IAction<TResult>> selector)
{
return new SelectManyActionAsync<TSource, TResult>(action, selector);
var selectMany = SM.Create(source, SM.Execute<Task<TSource>>(), selector, SM.ExecuteAsync<TResult>());
return selectMany.ToAction();
}

/// <summary>
/// Projects the result of an asynchronous action into a new asynchronous action.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="action">The action which result is transformed</param>
/// <param name="source">The action which result is transformed</param>
/// <param name="selector">A transform function that returns a new action.</param>
/// <returns></returns>
public static IAction<Task<TResult>> SelectMany<TSource, TResult>(this IAction<Task<TSource>> action, Func<TSource, IAction<Task<TResult>>> selector)
public static IAction<Task<TResult>> SelectMany<TSource, TResult>(this IAction<Task<TSource>> source, Func<TSource, IAction<Task<TResult>>> selector)
{
return new SelectManyActionAsyncReturningAsync<TSource, TResult>(action, selector);
var selectMany = SM.Create(source, SM.Execute<Task<TSource>>(), selector, SM.ExecuteAsync<Task<TResult>>());
return selectMany.ToAction();
}

/// <summary>
/// Projects the result of an asynchronous action into a new action.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <param name="source">The action which result is transformed</param>
/// <param name="selector">A transform function that returns a new action.</param>
/// <returns></returns>
public static IAction<Task> SelectMany<TSource>(this IAction<Task<TSource>> source, Func<TSource, IAction<Task>> selector)
{
var selectMany = SM.Create(source, SM.Execute<Task<TSource>>(), selector, SM.ExecuteAsync<Task>());
return selectMany.ToAction();
}

/// <summary>
/// Projects the result of an asynchronous action into a new question
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="action">The action which result is transformed</param>
/// <param name="source">The action which result is transformed</param>
/// <param name="selector">A transform function that returns a new action.</param>
/// <returns></returns>
public static IQuestion<Task<TResult>> SelectMany<TSource, TResult>(this IAction<Task<TSource>> action, Func<TSource, IQuestion<TResult>> selector)
public static IQuestion<Task<TResult>> SelectMany<TSource, TResult>(this IAction<Task<TSource>> source, Func<TSource, IQuestion<TResult>> selector)
{
return new SelectManyActionAsyncToQuestion<TSource, TResult>(action, selector);
var selectMany = SM.Create(source, SM.Execute<Task<TSource>>(), selector, SM.AsksForAsync<TResult>());
return selectMany.ToQuestion();
}

/// <summary>
/// Projects the result of an action into a new asynchronous question.
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TResult"></typeparam>
/// <param name="action">The action which result is transformed</param>
/// <param name="source">The action which result is transformed</param>
/// <param name="selector">A transform function that returns a new action.</param>
/// <returns></returns>
public static IQuestion<Task<TResult>> SelectMany<TSource, TResult>(this IAction<Task<TSource>> source, Func<TSource, IQuestion<Task<TResult>>> selector)
{
var selectMany = SM.Create(source, SM.Execute<Task<TSource>>(), selector, SM.AsksForAsync<Task<TResult>>());
return selectMany.ToQuestion();
}

/// <summary>
/// Projects the result of an asynchronous action into a new action.
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="source">The action which result is transformed</param>
/// <param name="selector">A transform function that returns a new action.</param>
/// <returns></returns>
public static IAction<Task<TResult>> SelectMany<TResult>(this IAction<Task> source, Func<IAction<TResult>> selector)
{
var selectMany = SM.Create(source, SM.Execute<Task>(), selector, SM.ExecuteAsync<TResult>());
return selectMany.ToAction();
}

/// <summary>
/// Projects the result of an asynchronous action into a new action.
/// </summary>
/// <param name="source">The action which result is transformed</param>
/// <param name="selector">A transform function that returns a new action.</param>
/// <returns></returns>
public static IAction<Task> SelectMany(this IAction<Task> source, Func<IAction<Task>> selector)
{
var selectMany = SM.Create(source, SM.Execute<Task>(), selector, SM.ExecuteAsync<Task>());
return selectMany.ToAction();
}

/// <summary>
/// Projects the result of an asynchronous action into a new action.
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="source">The action which result is transformed</param>
/// <param name="selector">A transform function that returns a new action.</param>
/// <returns></returns>
public static IAction<Task<TResult>> SelectMany<TResult>(this IAction<Task> source, Func<IAction<Task<TResult>>> selector)
{
var selectMany = SM.Create(source, SM.Execute<Task>(), selector, SM.ExecuteAsync<Task<TResult>>());
return selectMany.ToAction();
}

/// <summary>
/// Projects the result of an asynchronous action into a new question.
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="source">The action which result is transformed</param>
/// <param name="selector">A transform function that returns a new action.</param>
/// <returns></returns>
public static IQuestion<Task<TResult>> SelectMany<TResult>(this IAction<Task> source, Func<IQuestion<TResult>> selector)
{
var selectMany = SM.Create(source, SM.Execute<Task>(), selector, SM.AsksForAsync<TResult>());
return selectMany.ToQuestion();
}

/// <summary>
/// Projects the result of an asynchronous action into a new question.
/// </summary>
/// <typeparam name="TResult"></typeparam>
/// <param name="source">The action which result is transformed</param>
/// <param name="selector">A transform function that returns a new action.</param>
/// <returns></returns>
public static IQuestion<Task<TResult>> SelectMany<TSource, TResult>(this IAction<Task<TSource>> action, Func<TSource, IQuestion<Task<TResult>>> selector)
public static IQuestion<Task<TResult>> SelectMany<TResult>(this IAction<Task> source, Func<IQuestion<Task<TResult>>> selector)
{
return new SelectManyActionAsyncToQuestionAsync<TSource, TResult>(action, selector);
var selectMany = SM.Create(source, SM.Execute<Task>(), selector, SM.AsksForAsync<Task<TResult>>());
return selectMany.ToQuestion();
}
#endregion

Expand Down
104 changes: 104 additions & 0 deletions src/Tranquire/Extensions/SelectMany.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;

namespace Tranquire.Extensions
Expand Down Expand Up @@ -38,6 +39,7 @@ public TResult Apply(IActor actor)

internal static class SelectMany
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ISelectMany<TResult> Create<TActionSource, TSource, TActionResult, TResult>(
TActionSource source,
Func<IActor, TActionSource, TSource> applySource,
Expand All @@ -47,9 +49,19 @@ Func<IActor, TActionResult, TResult> applyResult
where TActionSource : class, INamed
where TActionResult : class
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
if (selector is null)
{
throw new ArgumentNullException(nameof(selector));
}

return new SelectMany<TActionSource, TSource, TActionResult, TResult>(source, applySource, selector, applyResult);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ISelectMany<Task<TResult>> Create<TActionSource, TSource, TActionResult, TResult>(
TActionSource source,
Func<IActor, TActionSource, Task<TSource>> applySource,
Expand All @@ -59,6 +71,15 @@ Func<IActor, Task<TActionResult>, Task<TResult>> applyResult
where TActionSource : class, INamed
where TActionResult : class
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
if (selector is null)
{
throw new ArgumentNullException(nameof(selector));
}

Func<Task<TSource>, Task<TActionResult>> selectorAsync = async sourceTask =>
{
var s = await sourceTask;
Expand All @@ -67,18 +88,101 @@ Func<IActor, Task<TActionResult>, Task<TResult>> applyResult
return Create(source, applySource, selectorAsync, applyResult);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ISelectMany<Task<TResult>> Create<TActionSource, TActionResult, TResult>(
TActionSource source,
Func<IActor, TActionSource, Task> applySource,
Func<TActionResult> selector,
Func<IActor, Task<TActionResult>, Task<TResult>> applyResult
)
where TActionSource : class, INamed
where TActionResult : class
{
if (source is null)
{
throw new ArgumentNullException(nameof(source));
}
if (selector is null)
{
throw new ArgumentNullException(nameof(selector));
}

Func<Task, Task<TActionResult>> selectorAsync = async sourceTask =>
{
await sourceTask;
return selector();
};
return Create(source, applySource, selectorAsync, applyResult);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Func<IActor, IQuestion<T>, T> AsksFor<T>() => (actor, q) => actor.AsksFor(q);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Func<IActor, Task<IQuestion<T>>, Task<T>> AsksForAsync<T>() => async (actor, questionTask) =>
{
var question = await questionTask;
return actor.AsksFor(question);
};

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Func<IActor, IAction<T>, T> Execute<T>() => (actor, q) => actor.Execute(q);

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Func<IActor, Task<IAction<T>>, Task<T>> ExecuteAsync<T>() => async (actor, actionTask) =>
{
var action = await actionTask;
return actor.Execute(action);
};
}

internal static class SelectManyExtensions
{
public static IAction<TResult> ToAction<TResult>(this ISelectMany<TResult> selectMany)
{
return Actions.Create(
selectMany.Name,
actor => selectMany.Apply(actor));
}

public static IAction<Task<TResult>> ToAction<TResult>(this ISelectMany<Task<Task<TResult>>> selectMany)
{
return Actions.Create(
selectMany.Name,
async actor =>
{
var task = await selectMany.Apply(actor);
return await task;
});
}

public static IAction<Task> ToAction(this ISelectMany<Task<Task>> selectMany)
{
return Actions.Create(
selectMany.Name,
async actor =>
{
var task = await selectMany.Apply(actor);
await task;
});
}

public static IQuestion<TResult> ToQuestion<TResult>(this ISelectMany<TResult> selectMany)
{
return Questions.Create(
selectMany.Name,
actor => selectMany.Apply(actor));
}

public static IQuestion<Task<TResult>> ToQuestion<TResult>(this ISelectMany<Task<Task<TResult>>> selectMany)
{
return Questions.Create(
selectMany.Name,
async actor =>
{
var task = await selectMany.Apply(actor);
return await task;
});
}
}
}
33 changes: 0 additions & 33 deletions src/Tranquire/Extensions/SelectManyAction.cs

This file was deleted.

Loading

0 comments on commit 8c629dd

Please sign in to comment.