using System.Collections; using System.Diagnostics; namespace InnovEnergy.Lib.Utils; public readonly struct Maybe<T> : IReadOnlyCollection<T> { private T Value { get; } public Boolean HasValue { get; } internal Maybe(T value, Boolean hasValue) { HasValue = hasValue; Value = value; } public static Maybe<T> Nothing { get; } = new Maybe<T>(default!, false); public T IfNothing(T t) => HasValue ? Value : t; public Maybe<R> Select<R>(Func<T, R> map) { return HasValue ? map(Value) : Maybe<R>.Nothing; } public IEnumerator<T> GetEnumerator() { if (Value != null) yield return Value; } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); public static implicit operator Maybe<T>(T? t) { Debug.Assert(typeof(T).IsClass); return new Maybe<T>(t!, t != null); } public Maybe<T> Do(Action<T> action) { if (HasValue) action(Value); return this; } public Int32 Count => HasValue ? 1 : 0; public override String ToString() => HasValue ? Value!.ToString()! : "Nothing"; public override Int32 GetHashCode() => HasValue ? Value!.GetHashCode() : 0; public override Boolean Equals(Object? obj) => obj is Maybe<T> other && Equals(other); public Boolean Equals(Maybe<T> other) => EqualityComparer<T>.Default.Equals(Value, other.Value) && HasValue == other.HasValue; public static Boolean operator ==(Maybe<T> left, Maybe<T> right) => left.Equals(right); public static Boolean operator !=(Maybe<T> left, Maybe<T> right) => !left.Equals(right); } public static class MaybeExtensions { public static Maybe<T> Maybe<T>(this IEnumerable<T> ts) where T : class { if (ts is Maybe<T> mb) return mb; return ts.SingleOrDefault().Maybe(); } public static Maybe<T> Maybe<T>(this T? t) where T : class { return new Maybe<T>(t!, t != null); } public static Maybe<T> Maybe<T>(this Nullable<T> t) where T: struct { return new Maybe<T>(t ?? default, t.HasValue); } } public static class MaybeEnumerableExtensions { public static IEnumerable<T> Flatten<T>(this IEnumerable<Maybe<T>> src) => src.SelectMany(s => s); // public static Maybe<T> FirstMaybe<T>(this IEnumerable<T> t) where T: class // { // using var enumerator = t.GetEnumerator(); // // return enumerator.MoveNext() // ? enumerator.Current // : null; // } // // public static Maybe<T> FirstMaybe<T>(this IEnumerable<T> t, Func<T, Boolean> predicate) where T: class // { // return t.Where(predicate).FirstMaybe(); // } // // public static Maybe<T> SingleMaybe<T>(this IEnumerable<T> t) where T: class // { // using var enumerator = t.GetEnumerator(); // // if (!enumerator.MoveNext()) // return Maybe<T>.Nothing; // // var single = enumerator.Current; // // if (enumerator.MoveNext()) // throw new InvalidOperationException("More than a single element encountered"); // // return single.Maybe(); // } // // public static Maybe<T> SingleMaybe<T>(this IEnumerable<T> t, Func<T, Boolean> predicate) where T: class // { // return t.Where(predicate).SingleMaybe(); // } // // public static Maybe<T> FirstMaybe<T>(this IEnumerable<Nullable<T>> ts) where T: struct // { // using var enumerator = ts.GetEnumerator(); // // return enumerator.MoveNext() && enumerator.Current.HasValue // ? enumerator.Current.Value // : Maybe<T>.Nothing; // } // // public static Maybe<T> FirstMaybe<T>(this IEnumerable<Nullable<T>> ts, Func<T?, Boolean> predicate) where T: struct // { // return ts.Where(predicate).FirstMaybe(); // } // // public static Maybe<T> SingleMaybe<T>(this IEnumerable<Nullable<T>> ts) where T: struct // { // using var enumerator = ts.GetEnumerator(); // // if (!enumerator.MoveNext()) // return Maybe<T>.Nothing; // // var single = enumerator.Current; // // if (enumerator.MoveNext()) // throw new InvalidOperationException("More than a single element encountered"); // // return single.Maybe(); // } // // public static Maybe<T> SingleMaybe<T>(this IEnumerable<Nullable<T>> ts, Func<T?, Boolean> predicate) where T: struct // { // return ts.Where(predicate).SingleMaybe(); // } }