using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading.Tasks.Sources;

namespace System.Threading.Tasks
{
	[AsyncMethodBuilder(typeof(AsyncValueTaskMethodBuilder))]
	[IsReadOnlyAttribute{47CF8CD7-B8BF-49E4-8755-713977DC796F}]
	[StructLayout(LayoutKind.Auto)]
	public struct ValueTask : IEquatable<ValueTask>
	{
		internal static Task CompletedTask { get; } = Task.Delay(0);

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public ValueTask(Task task)
		{
			if (task == null)
			{
				ThrowHelper.ThrowArgumentNullException(ExceptionArgument.task);
			}
			this._obj = task;
			this._continueOnCapturedContext = true;
			this._token = 0;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public ValueTask(IValueTaskSource source, short token)
		{
			if (source == null)
			{
				ThrowHelper.ThrowArgumentNullException(ExceptionArgument.source);
			}
			this._obj = source;
			this._token = token;
			this._continueOnCapturedContext = true;
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		private ValueTask(object obj, short token, bool continueOnCapturedContext)
		{
			this._obj = obj;
			this._token = token;
			this._continueOnCapturedContext = continueOnCapturedContext;
		}

		public override int GetHashCode()
		{
			object obj = this._obj;
			if (obj == null)
			{
				return 0;
			}
			return obj.GetHashCode();
		}

		public override bool Equals(object obj)
		{
			return obj is ValueTask && this.Equals((ValueTask)obj);
		}

		public bool Equals(ValueTask other)
		{
			return this._obj == other._obj && this._token == other._token;
		}

		public static bool operator ==(ValueTask left, ValueTask right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(ValueTask left, ValueTask right)
		{
			return !left.Equals(right);
		}

		public Task AsTask()
		{
			object obj = this._obj;
			Task task;
			if (obj != null)
			{
				if ((task = obj as Task) == null)
				{
					return this.GetTaskForValueTaskSource(Unsafe.As<IValueTaskSource>(obj));
				}
			}
			else
			{
				task = ValueTask.<CompletedTask>k__BackingField;
			}
			return task;
		}

		public ValueTask Preserve()
		{
			if (this._obj != null)
			{
				return new ValueTask(this.AsTask());
			}
			return this;
		}

		private Task GetTaskForValueTaskSource(IValueTaskSource t)
		{
			ValueTaskSourceStatus status = t.GetStatus(this._token);
			if (status != ValueTaskSourceStatus.Pending)
			{
				Task task;
				try
				{
					t.GetResult(this._token);
					task = ValueTask.<CompletedTask>k__BackingField;
				}
				catch (Exception ex)
				{
					if (status == ValueTaskSourceStatus.Canceled)
					{
						task = ValueTask.s_canceledTask;
					}
					else
					{
						TaskCompletionSource<bool> taskCompletionSource = new TaskCompletionSource<bool>();
						taskCompletionSource.TrySetException(ex);
						task = taskCompletionSource.Task;
					}
				}
				return task;
			}
			ValueTask.ValueTaskSourceAsTask valueTaskSourceAsTask = new ValueTask.ValueTaskSourceAsTask(t, this._token);
			return valueTaskSourceAsTask.Task;
		}

		public bool IsCompleted
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				object obj = this._obj;
				if (obj == null)
				{
					return true;
				}
				Task task;
				if ((task = obj as Task) != null)
				{
					return task.IsCompleted;
				}
				return Unsafe.As<IValueTaskSource>(obj).GetStatus(this._token) > ValueTaskSourceStatus.Pending;
			}
		}

		public bool IsCompletedSuccessfully
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				object obj = this._obj;
				if (obj == null)
				{
					return true;
				}
				Task task;
				if ((task = obj as Task) != null)
				{
					return task.Status == TaskStatus.RanToCompletion;
				}
				return Unsafe.As<IValueTaskSource>(obj).GetStatus(this._token) == ValueTaskSourceStatus.Succeeded;
			}
		}

		public bool IsFaulted
		{
			get
			{
				object obj = this._obj;
				if (obj == null)
				{
					return false;
				}
				Task task;
				if ((task = obj as Task) != null)
				{
					return task.IsFaulted;
				}
				return Unsafe.As<IValueTaskSource>(obj).GetStatus(this._token) == ValueTaskSourceStatus.Faulted;
			}
		}

		public bool IsCanceled
		{
			get
			{
				object obj = this._obj;
				if (obj == null)
				{
					return false;
				}
				Task task;
				if ((task = obj as Task) != null)
				{
					return task.IsCanceled;
				}
				return Unsafe.As<IValueTaskSource>(obj).GetStatus(this._token) == ValueTaskSourceStatus.Canceled;
			}
		}

		[StackTraceHidden]
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		internal void ThrowIfCompletedUnsuccessfully()
		{
			object obj = this._obj;
			if (obj != null)
			{
				Task task;
				if ((task = obj as Task) != null)
				{
					task.GetAwaiter().GetResult();
					return;
				}
				Unsafe.As<IValueTaskSource>(obj).GetResult(this._token);
			}
		}

		public ValueTaskAwaiter GetAwaiter()
		{
			return new ValueTaskAwaiter(this);
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public ConfiguredValueTaskAwaitable ConfigureAwait(bool continueOnCapturedContext)
		{
			return new ConfiguredValueTaskAwaitable(new ValueTask(this._obj, this._token, continueOnCapturedContext));
		}

		private static readonly Task s_canceledTask = Task.Delay(-1, new CancellationToken(true));

		internal readonly object _obj;

		internal readonly short _token;

		internal readonly bool _continueOnCapturedContext;

		private sealed class ValueTaskSourceAsTask : TaskCompletionSource<bool>
		{
			public ValueTaskSourceAsTask(IValueTaskSource source, short token)
			{
				this._token = token;
				this._source = source;
				source.OnCompleted(ValueTask.ValueTaskSourceAsTask.s_completionAction, this, token, ValueTaskSourceOnCompletedFlags.None);
			}

			private static readonly Action<object> s_completionAction = delegate(object state)
			{
				ValueTask.ValueTaskSourceAsTask valueTaskSourceAsTask;
				IValueTaskSource source;
				if ((valueTaskSourceAsTask = state as ValueTask.ValueTaskSourceAsTask) != null && (source = valueTaskSourceAsTask._source) != null)
				{
					valueTaskSourceAsTask._source = null;
					ValueTaskSourceStatus status = source.GetStatus(valueTaskSourceAsTask._token);
					try
					{
						source.GetResult(valueTaskSourceAsTask._token);
						valueTaskSourceAsTask.TrySetResult(false);
					}
					catch (Exception ex)
					{
						if (status == ValueTaskSourceStatus.Canceled)
						{
							valueTaskSourceAsTask.TrySetCanceled();
						}
						else
						{
							valueTaskSourceAsTask.TrySetException(ex);
						}
					}
					return;
				}
				ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.state);
			};

			private object _source;

			private readonly short _token;
		}
	}
}
