Created
November 5, 2015 00:06
-
-
Save ReubenBond/bbebc160775555d010da to your computer and use it in GitHub Desktop.
ObjectTask: movified version of ValueTask for use in generated dispatchers
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
public struct ObjectTask : IEquatable<ObjectTask> | |
{ | |
private static object GetResult<TResult>(Task typedTask) | |
{ | |
return ((Task<TResult>)typedTask).GetAwaiter().GetResult(); | |
} | |
private static object GetResult(Task untypedTask) | |
{ | |
untypedTask?.GetAwaiter().GetResult(); | |
return default(object); | |
} | |
/// <summary> | |
/// The task, whcih will be non-null iff the operation didn't complete successfully synchronously. | |
/// </summary> | |
private readonly Task task; | |
/// <summary> | |
/// The delegate used to retrieve the result, waiting on the task if required. | |
/// </summary> | |
private readonly Func<Task, object> getResult; | |
/// <summary> | |
/// The result to be used if the operation completed successfully synchronously. | |
/// </summary> | |
private readonly object result; | |
public static ObjectTask Create<TResult>(Task<TResult> task) | |
{ | |
return new ObjectTask(task, null, GetResult<TResult>); | |
} | |
public static ObjectTask Create(Task task) | |
{ | |
return new ObjectTask(task, null, GetResult); | |
} | |
public static ObjectTask Create<TResult>(TResult result) | |
{ | |
return new ObjectTask(null, result, GetResult); | |
} | |
/// <summary> | |
/// Initialize the TaskValue with a <see cref="Task"/> that represents | |
/// the non-successful or incomplete operation. | |
/// </summary> | |
/// <param name="task"> | |
/// The task. | |
/// </param> | |
/// <param name="result"> | |
/// The result. | |
/// </param> | |
/// <param name="getResult"> | |
/// The delegate used to retrieve the result from the task. | |
/// </param> | |
private ObjectTask(Task task, object result, Func<Task, object> getResult) | |
{ | |
Debug.Assert(getResult != null); | |
this.result = result; | |
this.task = task; | |
this.getResult = getResult; | |
} | |
/// <summary>Returns the hash code for this instance.</summary> | |
public override int GetHashCode() | |
{ | |
return this.task?.GetHashCode() ?? this.result?.GetHashCode() ?? 0; | |
} | |
/// <summary>Returns a value indicating whether this value is equal to a specified <see cref="object"/>.</summary> | |
public override bool Equals(object obj) | |
{ | |
return obj is ObjectTask && this.Equals((ObjectTask)obj); | |
} | |
/// <summary>Returns a value indicating whether this value is equal to a specified <see cref="ObjectTask"/> value.</summary> | |
public bool Equals(ObjectTask other) | |
{ | |
if (this.task != null || other.task != null) | |
{ | |
return this.task == other.task; | |
} | |
if (this.result == null) | |
{ | |
return other.result == null; | |
} | |
else | |
{ | |
return other.result != null && this.result.Equals(other.result); | |
} | |
} | |
/// <summary>Returns a value indicating whether two <see cref="ObjectTask"/> values are equal.</summary> | |
public static bool operator ==(ObjectTask left, ObjectTask right) | |
{ | |
return left.Equals(right); | |
} | |
/// <summary>Returns a value indicating whether two <see cref="ObjectTask"/> values are not equal.</summary> | |
public static bool operator !=(ObjectTask left, ObjectTask right) | |
{ | |
return !left.Equals(right); | |
} | |
/// <summary> | |
/// Gets a <see cref="Task{TResult}"/> object to represent this TaskValue. It will | |
/// either return the wrapped task object if one exists, or it'll manufacture a new | |
/// task object to represent the result. | |
/// </summary> | |
[Pure] | |
public Task AsTask() | |
{ | |
return this.task ?? Task.FromResult(this.result); | |
} | |
/// <summary>Gets whether the TaskValue represents a successfully completed operation.</summary> | |
public bool IsRanToCompletion => this.task == null || this.task.Status == TaskStatus.RanToCompletion; | |
/// <summary>Gets the result.</summary> | |
public object Result => this.task == null ? this.result : this.getResult(this.task); | |
/// <summary>Gets an awaiter for this value.</summary> | |
public ObjectTaskAwaiter GetAwaiter() | |
{ | |
return new ObjectTaskAwaiter(this, continueOnCapturedContext: true); | |
} | |
/// <summary>Configures an awaiter for this value.</summary> | |
/// <param name="continueOnCapturedContext">true to attempt to marshal the continuation back to the captured context; otherwise, false.</param> | |
public ObjectTaskAwaiter ConfigureAwait(bool continueOnCapturedContext) | |
{ | |
return new ObjectTaskAwaiter(this, continueOnCapturedContext: continueOnCapturedContext); | |
} | |
/// <summary>Gets a TaskStatus for the debugger to display.</summary> | |
private TaskStatus DebuggerStatus => this.task?.Status ?? TaskStatus.RanToCompletion; | |
/// <summary>Gets a result string for the debugger to display.</summary> | |
private string DebuggerResult => this.task == null | |
? this.result.ToString() | |
: this.task.Status == TaskStatus.RanToCompletion | |
? this.Result.ToString() | |
: "Task result not available."; | |
/// <summary> | |
/// Provides an awaiter for an ObjectTask. | |
/// </summary> | |
public struct ObjectTaskAwaiter : ICriticalNotifyCompletion | |
{ | |
/// <summary> | |
/// The value being awaited. | |
/// </summary> | |
private readonly ObjectTask value; | |
/// <summary> | |
/// The value to pass to ConfigureAwait. | |
/// </summary> | |
private readonly bool continueOnCapturedContext; | |
/// <summary>Initializes the awaiter.</summary> | |
/// <param name="value">The value to be awaited.</param> | |
/// <param name="continueOnCapturedContext">The value to pass to ConfigureAwait.</param> | |
public ObjectTaskAwaiter(ObjectTask value, bool continueOnCapturedContext) | |
{ | |
this.value = value; | |
this.continueOnCapturedContext = continueOnCapturedContext; | |
} | |
/// <summary> | |
/// Returns this awaiter. | |
/// </summary> | |
public ObjectTaskAwaiter GetAwaiter() { return this; } | |
/// <summary>Gets whether the TaskValue has completed.</summary> | |
public bool IsCompleted => this.value.task == null || this.value.task.IsCompleted; | |
/// <summary>Gets the result of the TaskValue.</summary> | |
public object GetResult() | |
{ | |
return this.value.Result; | |
} | |
/// <summary>Schedules the continuation action for this TaskValue.</summary> | |
public void OnCompleted(Action continuation) | |
{ | |
this.value.AsTask().ConfigureAwait(this.continueOnCapturedContext).GetAwaiter().OnCompleted(continuation); | |
} | |
/// <summary>Schedules the continuation action for this TaskValue.</summary> | |
public void UnsafeOnCompleted(Action continuation) | |
{ | |
this.value.AsTask().ConfigureAwait(this.continueOnCapturedContext).GetAwaiter().UnsafeOnCompleted(continuation); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment