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