Skip to content

Commit

Permalink
Added extra converts to async delegates
Browse files Browse the repository at this point in the history
  • Loading branch information
sakno committed Sep 26, 2024
1 parent d7b396b commit 71c4beb
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 0 deletions.
11 changes: 11 additions & 0 deletions src/DotNext.Tests/DelegateHelpersTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,17 @@ public static async Task ToAsync4()
func = new Func<int, int, int>(static (_, _) => throw new Exception()).ToAsync();
await ThrowsAsync<Exception>(func.Invoke(42, 42, new(canceled: false)).AsTask);
}

[Fact]
public static async Task ToAsync5()
{
var func = Func.Identity<int>().ToAsync();
Equal(42, await func.Invoke(42, new(canceled: false)));
True(func.Invoke(42, new(canceled: true)).IsCanceled);

func = new Func<int, int>(static _ => throw new Exception()).ToAsync();
await ThrowsAsync<Exception>(func.Invoke(42, new(canceled: false)).AsTask);
}

[Fact]
public static void HideReturnValue1()
Expand Down
73 changes: 73 additions & 0 deletions src/DotNext/DelegateHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,43 @@ private static ValueTask Invoke<T>(this Action<T> action, T arg, CancellationTok
return task;
}

/// <summary>
/// Converts function to async delegate.
/// </summary>
/// <param name="action">Synchronous function.</param>
/// <typeparam name="T">The type of the argument to be passed to the action.</typeparam>
/// <typeparam name="TResult">The type of the return value.</typeparam>
/// <returns>The asynchronous function that wraps <paramref name="action"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="action"/> is <see langword="null"/>.</exception>
public static Func<T, CancellationToken, ValueTask<TResult>> ToAsync<T, TResult>(this Func<T, TResult> action)
{
ArgumentNullException.ThrowIfNull(action);

return action.Invoke;
}

private static ValueTask<TResult> Invoke<T, TResult>(this Func<T, TResult> action, T arg, CancellationToken token)
{
ValueTask<TResult> task;
if (token.IsCancellationRequested)
{
task = ValueTask.FromCanceled<TResult>(token);
}
else
{
try
{
task = new(action.Invoke(arg));
}
catch (Exception e)
{
task = ValueTask.FromException<TResult>(e);
}
}

return task;
}

/// <summary>
/// Converts action to async delegate.
/// </summary>
Expand Down Expand Up @@ -161,6 +198,42 @@ private static ValueTask Invoke(this Action action, CancellationToken token)

return task;
}

/// <summary>
/// Converts function to async delegate.
/// </summary>
/// <typeparam name="TResult">The type of the return value.</typeparam>
/// <param name="func">Synchronous function.</param>
/// <returns>The asynchronous function that wraps <paramref name="func"/>.</returns>
/// <exception cref="ArgumentNullException"><paramref name="func"/> is <see langword="null"/>.</exception>
public static Func<CancellationToken, ValueTask<TResult>> ToAsync<TResult>(this Func<TResult> func)
{
ArgumentNullException.ThrowIfNull(func);

return func.Invoke;
}

private static ValueTask<TResult> Invoke<TResult>(this Func<TResult> func, CancellationToken token)
{
ValueTask<TResult> task;
if (token.IsCancellationRequested)
{
task = ValueTask.FromCanceled<TResult>(token);
}
else
{
try
{
task = new(func.Invoke());
}
catch (Exception e)
{
task = ValueTask.FromException<TResult>(e);
}
}

return task;
}

/// <summary>
/// Converts action to async delegate.
Expand Down

0 comments on commit 71c4beb

Please sign in to comment.