106 lines
3.1 KiB
C#
106 lines
3.1 KiB
C#
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 {
|
|
/// <summary>
|
|
/// Provides helper methods that allow us to use terser code elsewhere.
|
|
/// </summary>
|
|
public static class InternalExtensions {
|
|
/// <summary>
|
|
/// Ensures a task (even null) is awaitable.
|
|
/// </summary>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <param name="task"></param>
|
|
/// <returns></returns>
|
|
public static Task<T> Safe<T>(this Task<T> task) {
|
|
return task ?? Task.FromResult<T>(default(T));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Ensures a task (even null) is awaitable.
|
|
/// </summary>
|
|
/// <param name="task"></param>
|
|
/// <returns></returns>
|
|
public static Task Safe(this Task task) {
|
|
return task ?? Task.FromResult<object>(null);
|
|
}
|
|
|
|
public delegate void PartialAccessor<T>(ref T arg);
|
|
|
|
public static TValue GetOrDefault<TKey, TValue>(this IDictionary<TKey, TValue> self,
|
|
TKey key,
|
|
TValue defaultValue) {
|
|
TValue value;
|
|
if (self.TryGetValue(key, out value)) {
|
|
return value;
|
|
}
|
|
return defaultValue;
|
|
}
|
|
|
|
public static bool CollectionsEqual<T>(this IEnumerable<T> a, IEnumerable<T> b) {
|
|
return Object.Equals(a, b) ||
|
|
(a != null && b != null &&
|
|
a.SequenceEqual(b));
|
|
}
|
|
|
|
public static Task<TResult> OnSuccess<TIn, TResult>(this Task<TIn> task,
|
|
Func<Task<TIn>, TResult> continuation) {
|
|
return ((Task)task).OnSuccess(t => continuation((Task<TIn>)t));
|
|
}
|
|
|
|
public static Task OnSuccess<TIn>(this Task<TIn> task, Action<Task<TIn>> continuation) {
|
|
return task.OnSuccess((Func<Task<TIn>, object>)(t => {
|
|
continuation(t);
|
|
return null;
|
|
}));
|
|
}
|
|
|
|
public static Task<TResult> OnSuccess<TResult>(this Task task,
|
|
Func<Task, TResult> 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<TResult>();
|
|
tcs.SetCanceled();
|
|
return tcs.Task;
|
|
} else {
|
|
return Task.FromResult(continuation(t));
|
|
}
|
|
}).Unwrap();
|
|
}
|
|
|
|
public static Task OnSuccess(this Task task, Action<Task> continuation) {
|
|
return task.OnSuccess((Func<Task, object>)(t => {
|
|
continuation(t);
|
|
return null;
|
|
}));
|
|
}
|
|
|
|
public static Task WhileAsync(Func<Task<bool>> predicate, Func<Task> body) {
|
|
Func<Task> iterate = null;
|
|
iterate = () => {
|
|
return predicate().OnSuccess(t => {
|
|
if (!t.Result) {
|
|
return Task.FromResult(0);
|
|
}
|
|
return body().OnSuccess(_ => iterate()).Unwrap();
|
|
}).Unwrap();
|
|
};
|
|
return iterate();
|
|
}
|
|
}
|
|
}
|