-
-
Notifications
You must be signed in to change notification settings - Fork 802
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1125 from stakx/awaitable-factories
Create and deconstruct awaitables using dedicated factories (`IAwaitableFactory`)
- Loading branch information
Showing
15 changed files
with
297 additions
and
87 deletions.
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,29 @@ | ||
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors. | ||
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. | ||
|
||
namespace Moq.Async | ||
{ | ||
internal static class Awaitable | ||
{ | ||
/// <summary> | ||
/// Recursively gets the result of (i.e. "unwraps") completed awaitables | ||
/// until a value is found that isn't a successfully completed awaitable. | ||
/// </summary> | ||
/// <remarks> | ||
/// As an example, given <paramref name="obj"/> := <c>Task.FromResult(Task.FromResult(42))</c>, | ||
/// this method will return <c>42</c>. | ||
/// </remarks> | ||
/// <param name="obj">The (possibly awaitable) object to be "unwrapped".</param> | ||
public static object TryGetResultRecursive(object obj) | ||
{ | ||
if (obj != null | ||
&& AwaitableFactory.TryGet(obj.GetType()) is { } awaitableFactory | ||
&& awaitableFactory.TryGetResult(obj, out var result)) | ||
{ | ||
return result; | ||
} | ||
|
||
return obj; | ||
} | ||
} | ||
} |
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,47 @@ | ||
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors. | ||
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Threading.Tasks; | ||
|
||
namespace Moq.Async | ||
{ | ||
internal static class AwaitableFactory | ||
{ | ||
private static readonly Dictionary<Type, Func<Type, IAwaitableFactory>> Providers; | ||
|
||
static AwaitableFactory() | ||
{ | ||
AwaitableFactory.Providers = new Dictionary<Type, Func<Type, IAwaitableFactory>> | ||
{ | ||
[typeof(Task)] = awaitableType => TaskFactory.Instance, | ||
[typeof(ValueTask)] = awaitableType => ValueTaskFactory.Instance, | ||
[typeof(Task<>)] = awaitableType => AwaitableFactory.Create(typeof(TaskFactory<>), awaitableType), | ||
[typeof(ValueTask<>)] = awaitableType => AwaitableFactory.Create(typeof(ValueTaskFactory<>), awaitableType), | ||
}; | ||
} | ||
|
||
private static IAwaitableFactory Create(Type awaitableFactoryType, Type awaitableType) | ||
{ | ||
return (IAwaitableFactory)Activator.CreateInstance( | ||
awaitableFactoryType.MakeGenericType( | ||
awaitableType.GetGenericArguments())); | ||
} | ||
|
||
public static IAwaitableFactory TryGet(Type type) | ||
{ | ||
Debug.Assert(type != null); | ||
|
||
var key = type.IsConstructedGenericType ? type.GetGenericTypeDefinition() : type; | ||
|
||
if (AwaitableFactory.Providers.TryGetValue(key, out var provider)) | ||
{ | ||
return provider.Invoke(type); | ||
} | ||
|
||
return null; | ||
} | ||
} | ||
} |
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,34 @@ | ||
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors. | ||
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. | ||
|
||
using System; | ||
using System.Diagnostics; | ||
|
||
namespace Moq.Async | ||
{ | ||
/// <summary> | ||
/// Abstract base class that facilitates type-safe implementation of <see cref="IAwaitableFactory"/> | ||
/// for awaitables that do not produce a result when awaited. | ||
/// </summary> | ||
internal abstract class AwaitableFactory<TAwaitable> : IAwaitableFactory | ||
{ | ||
Type IAwaitableFactory.ResultType => typeof(void); | ||
|
||
public abstract TAwaitable CreateCompleted(); | ||
|
||
object IAwaitableFactory.CreateCompleted(object result) | ||
{ | ||
Debug.Assert(result == null); | ||
|
||
return this.CreateCompleted(); | ||
} | ||
|
||
bool IAwaitableFactory.TryGetResult(object awaitable, out object result) | ||
{ | ||
Debug.Assert(awaitable is TAwaitable); | ||
|
||
result = null; | ||
return false; | ||
} | ||
} | ||
} |
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,42 @@ | ||
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors. | ||
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. | ||
|
||
using System; | ||
using System.Diagnostics; | ||
|
||
namespace Moq.Async | ||
{ | ||
/// <summary> | ||
/// Abstract base class that facilitates type-safe implementation of <see cref="IAwaitableFactory"/> | ||
/// for awaitables that produce a result when awaited. | ||
/// </summary> | ||
internal abstract class AwaitableFactory<TAwaitable, TResult> : IAwaitableFactory | ||
{ | ||
public Type ResultType => typeof(TResult); | ||
|
||
public abstract TAwaitable CreateCompleted(TResult result); | ||
|
||
object IAwaitableFactory.CreateCompleted(object result) | ||
{ | ||
Debug.Assert(result is TResult || result == null); | ||
|
||
return this.CreateCompleted((TResult)result); | ||
} | ||
|
||
public abstract bool TryGetResult(TAwaitable awaitable, out TResult result); | ||
|
||
bool IAwaitableFactory.TryGetResult(object awaitable, out object result) | ||
{ | ||
Debug.Assert(awaitable is TAwaitable); | ||
|
||
if (this.TryGetResult((TAwaitable)awaitable, out var r)) | ||
{ | ||
result = r; | ||
return true; | ||
} | ||
|
||
result = null; | ||
return false; | ||
} | ||
} | ||
} |
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,16 @@ | ||
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors. | ||
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. | ||
|
||
using System; | ||
|
||
namespace Moq.Async | ||
{ | ||
internal interface IAwaitableFactory | ||
{ | ||
Type ResultType { get; } | ||
|
||
object CreateCompleted(object result = null); | ||
|
||
bool TryGetResult(object awaitable, out object result); | ||
} | ||
} |
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,21 @@ | ||
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors. | ||
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. | ||
|
||
using System.Threading.Tasks; | ||
|
||
namespace Moq.Async | ||
{ | ||
internal sealed class TaskFactory : AwaitableFactory<Task> | ||
{ | ||
public static readonly TaskFactory Instance = new TaskFactory(); | ||
|
||
private TaskFactory() | ||
{ | ||
} | ||
|
||
public override Task CreateCompleted() | ||
{ | ||
return Task.FromResult<object>(default); | ||
} | ||
} | ||
} |
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,27 @@ | ||
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors. | ||
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. | ||
|
||
using System.Threading.Tasks; | ||
|
||
namespace Moq.Async | ||
{ | ||
internal sealed class TaskFactory<TResult> : AwaitableFactory<Task<TResult>, TResult> | ||
{ | ||
public override Task<TResult> CreateCompleted(TResult result) | ||
{ | ||
return Task.FromResult(result); | ||
} | ||
|
||
public override bool TryGetResult(Task<TResult> task, out TResult result) | ||
{ | ||
if (task.Status == TaskStatus.RanToCompletion) | ||
{ | ||
result = task.Result; | ||
return true; | ||
} | ||
|
||
result = default; | ||
return false; | ||
} | ||
} | ||
} |
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,21 @@ | ||
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors. | ||
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. | ||
|
||
using System.Threading.Tasks; | ||
|
||
namespace Moq.Async | ||
{ | ||
internal sealed class ValueTaskFactory : AwaitableFactory<ValueTask> | ||
{ | ||
public static readonly ValueTaskFactory Instance = new ValueTaskFactory(); | ||
|
||
private ValueTaskFactory() | ||
{ | ||
} | ||
|
||
public override ValueTask CreateCompleted() | ||
{ | ||
return default; | ||
} | ||
} | ||
} |
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,27 @@ | ||
// Copyright (c) 2007, Clarius Consulting, Manas Technology Solutions, InSTEDD, and Contributors. | ||
// All rights reserved. Licensed under the BSD 3-Clause License; see License.txt. | ||
|
||
using System.Threading.Tasks; | ||
|
||
namespace Moq.Async | ||
{ | ||
internal sealed class ValueTaskFactory<TResult> : AwaitableFactory<ValueTask<TResult>, TResult> | ||
{ | ||
public override ValueTask<TResult> CreateCompleted(TResult result) | ||
{ | ||
return new ValueTask<TResult>(result); | ||
} | ||
|
||
public override bool TryGetResult(ValueTask<TResult> valueTask, out TResult result) | ||
{ | ||
if (valueTask.IsCompletedSuccessfully) | ||
{ | ||
result = valueTask.Result; | ||
return true; | ||
} | ||
|
||
result = default; | ||
return false; | ||
} | ||
} | ||
} |
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
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
Oops, something went wrong.