Skip to content

Instantly share code, notes, and snippets.

@ReubenBond
Created November 5, 2015 00:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ReubenBond/bbebc160775555d010da to your computer and use it in GitHub Desktop.
Save ReubenBond/bbebc160775555d010da to your computer and use it in GitHub Desktop.
ObjectTask: movified version of ValueTask for use in generated dispatchers
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