using System; namespace KitsuneCafe.System { public interface IOption { private static IOption none = new None(); public abstract bool IsSome { get; } public static IOption Some(T value) => new Some(value); public static IOption None() => none; public abstract T Unwrap(); public abstract IOption SelectMany(Func> func); public abstract IOption Select(Func func); public abstract IOption Where(Func predicate); public abstract TResult Match(Func ifSome, Func ifNone); public abstract T UnwrapOrDefault(T defaultValue = default); public abstract T UnwrapOrElse(Func func); public virtual IOption Do(Action func) { if (IsSome) { func(Unwrap()); } return this; } } public readonly struct Some : IOption { private readonly T value; public readonly bool IsSome => true; internal Some(T value) { this.value = value; } public IOption SelectMany(Func> func) { return func(value); } public T Unwrap() { return value; } public IOption Select(Func func) { return IOption.Some(func(value)); } public IOption Where(Func predicate) { if (predicate(value)) { return this; } return IOption.None(); } public TResult Match(Func ifSome, Func ifNone) { return ifSome(value); } public T UnwrapOrDefault(T defaultValue = default) { return value; } public T UnwrapOrElse(Func _func) { return value; } } public readonly struct None : IOption { public readonly bool IsSome => false; public IOption SelectMany(Func> func) { return IOption.None(); } public T Unwrap() { throw new InvalidOperationException("Attempted to unwrap value of None."); } public IOption Select(Func func) { return IOption.None(); } public IOption Where(Func predicate) { return IOption.None(); } public TResult Match(Func ifSome, Func ifNone) { return ifNone(); } public T UnwrapOrDefault(T defaultValue = default) { return defaultValue; } public T UnwrapOrElse(Func func) { return func(); } } }