155 lines
4.5 KiB
C#
155 lines
4.5 KiB
C#
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();
|
|
// }
|
|
}
|