using System;
using System.Collections.Generic;
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<TResult> : IEquatable<ValueTask<TResult>>
	{
		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public ValueTask(TResult result)
		{
			this._result = result;
			this._obj = null;
			this._continueOnCapturedContext = true;
			this._token = 0;
		}

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

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

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

		public override int GetHashCode()
		{
			if (this._obj != null)
			{
				return this._obj.GetHashCode();
			}
			if (this._result == null)
			{
				return 0;
			}
			TResult result = this._result;
			return result.GetHashCode();
		}

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

		public bool Equals(ValueTask<TResult> other)
		{
			if (this._obj == null && other._obj == null)
			{
				return EqualityComparer<TResult>.Default.Equals(this._result, other._result);
			}
			return this._obj == other._obj && this._token == other._token;
		}

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

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

		public Task<TResult> AsTask()
		{
			object obj = this._obj;
			if (obj == null)
			{
				return Task.FromResult<TResult>(this._result);
			}
			Task<TResult> task;
			if ((task = obj as Task<TResult>) != null)
			{
				return task;
			}
			return this.GetTaskForValueTaskSource(Unsafe.As<IValueTaskSource<TResult>>(obj));
		}

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

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

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

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

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

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

		public TResult Result
		{
			[MethodImpl(MethodImplOptions.AggressiveInlining)]
			get
			{
				object obj = this._obj;
				if (obj == null)
				{
					return this._result;
				}
				Task<TResult> task;
				if ((task = obj as Task<TResult>) != null)
				{
					return task.GetAwaiter().GetResult();
				}
				return Unsafe.As<IValueTaskSource<TResult>>(obj).GetResult(this._token);
			}
		}

		[MethodImpl(MethodImplOptions.AggressiveInlining)]
		public ValueTaskAwaiter<TResult> GetAwaiter()
		{
			return new ValueTaskAwaiter<TResult>(this);
		}

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

		public override string ToString()
		{
			if (this.IsCompletedSuccessfully)
			{
				TResult result = this.Result;
				if (result != null)
				{
					return result.ToString();
				}
			}
			return string.Empty;
		}

		private static Task<TResult> s_canceledTask;

		internal readonly object _obj;

		internal readonly TResult _result;

		internal readonly short _token;

		internal readonly bool _continueOnCapturedContext;

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

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

			private IValueTaskSource<TResult> _source;

			private readonly short _token;
		}
	}
}
