Innovenergy_trunk/csharp/Lib/Utils/Maybe.cs

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();
// }
}