using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Runtime.ExceptionServices; using System.Text; using System.Threading.Tasks; namespace LeanCloud.Storage.Internal { /// /// Provides helper methods that allow us to use terser code elsewhere. /// public static class InternalExtensions { /// /// Ensures a task (even null) is awaitable. /// /// /// /// public static Task Safe(this Task task) { return task ?? Task.FromResult(default(T)); } /// /// Ensures a task (even null) is awaitable. /// /// /// public static Task Safe(this Task task) { return task ?? Task.FromResult(null); } public delegate void PartialAccessor(ref T arg); public static TValue GetOrDefault(this IDictionary self, TKey key, TValue defaultValue) { TValue value; if (self.TryGetValue(key, out value)) { return value; } return defaultValue; } public static bool CollectionsEqual(this IEnumerable a, IEnumerable b) { return Object.Equals(a, b) || (a != null && b != null && a.SequenceEqual(b)); } public static Task OnSuccess(this Task task, Func, TResult> continuation) { return ((Task)task).OnSuccess(t => continuation((Task)t)); } public static Task OnSuccess(this Task task, Action> continuation) { return task.OnSuccess((Func, object>)(t => { continuation(t); return null; })); } public static Task OnSuccess(this Task task, Func continuation) { return task.ContinueWith(t => { if (t.IsFaulted) { var ex = t.Exception.Flatten(); if (ex.InnerExceptions.Count == 1) { ExceptionDispatchInfo.Capture(ex.InnerExceptions[0]).Throw(); } else { ExceptionDispatchInfo.Capture(ex).Throw(); } // Unreachable return Task.FromResult(default(TResult)); } else if (t.IsCanceled) { var tcs = new TaskCompletionSource(); tcs.SetCanceled(); return tcs.Task; } else { return Task.FromResult(continuation(t)); } }).Unwrap(); } public static Task OnSuccess(this Task task, Action continuation) { return task.OnSuccess((Func)(t => { continuation(t); return null; })); } public static Task WhileAsync(Func> predicate, Func body) { Func iterate = null; iterate = () => { return predicate().OnSuccess(t => { if (!t.Result) { return Task.FromResult(0); } return body().OnSuccess(_ => iterate()).Unwrap(); }).Unwrap(); }; return iterate(); } } }