using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Xml.Linq; namespace Jackett.Common.Utils { // Prefer built in NullReferenceException || ArgumentNullException || NoNullAllowedException public class NonNullException : Exception { public NonNullException() : base("Parameter cannot be null") { } } public class NonNull where T : class { public NonNull(T val) { // doesn't throw Exception? if (val == null) new NonNullException(); Value = val; } public static implicit operator T(NonNull n) => n.Value; private readonly T Value; } public static class GenericConversionExtensions { public static IEnumerable ToEnumerable(this T obj) => new T[] { obj }; public static NonNull ToNonNull(this T obj) where T : class => new NonNull(obj); } public static class EnumerableExtension { public static string AsString(this IEnumerable chars) => string.Concat(chars); public static T FirstIfSingleOrDefault(this IEnumerable enumerable, T replace = default) { //Avoid enumerating the whole array. //If enumerable.Count() < 2, takes whole array. var test = enumerable.Take(2).ToList(); return test.Count == 1 ? test[0] : replace; } public static IEnumerable Flatten(this IEnumerable> list) => list.SelectMany(x => x); } public static class CollectionExtension { // IEnumerable class above already does this. All ICollection are IEnumerable, so favor IEnumerable? public static bool IsEmpty(this ICollection obj) => obj.Count == 0; // obj == null || obj.IsEmpty() causes VS to suggest merging sequential checks // the result is obj?.IsEmpty() == true which returns false when null // Other options are obj?.IsEmpty() == true || obj == null Or (obj?.IsEmpty()).GetValueOrDefault(true) // All three options remove the suggestion and give the intended result of this function public static bool IsEmptyOrNull(this ICollection obj) => obj?.IsEmpty() ?? true; } public static class XElementExtension { public static XElement First(this XElement element, string name) => element.Descendants(name).First(); public static string FirstValue(this XElement element, string name) => element.First(name).Value; } public static class KeyValuePairsExtension { public static IDictionary ToDictionary(this IEnumerable> pairs) => pairs.ToDictionary(x => x.Key, x => x.Value); } public static class TaskExtensions { public static Task> Until(this IEnumerable> tasks, TimeSpan timeout) { var timeoutTask = Task.Delay(timeout); var aggregateTask = Task.WhenAll(tasks); var anyTask = Task.WhenAny(timeoutTask, aggregateTask); var continuation = anyTask.ContinueWith((_) => { var completedTasks = tasks.Where(t => t.Status == TaskStatus.RanToCompletion); var results = completedTasks.Select(t => t.Result); return results; }); return continuation; } } }