using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace SJK.Functional; public struct Option : IEquatable> { private readonly T? _value; [MemberNotNullWhen(true, nameof(_value))] public bool HasValue { get; } public static Option None => new(default, false); public static Option Some(T value) => new(value, true); private Option(T? value, bool hasValue) { Debug.Assert(!(value is null && hasValue), "Can not create an option with a null value had say it has one"); _value = value; HasValue = hasValue; } public T? Value => HasValue ? _value : throw new InvalidOperationException("Can not retrive value when there is no value."); // [MethodImpl(MethodImplOptions.AggressiveInlining)] public TResult Match(Func some, Func none) => HasValue ? some(_value) : none(); // [MethodImpl(MethodImplOptions.AggressiveInlining)] public Option Map(Func f) => HasValue ? Option.Some(f(_value)) : Option.None; // [MethodImpl(MethodImplOptions.AggressiveInlining)] public Option Bind(Func> f) => HasValue ? f(_value) : Option.None; // [MethodImpl(MethodImplOptions.AggressiveInlining)] public T OrDefault(T value) => HasValue ? _value : value; // [MethodImpl(MethodImplOptions.AggressiveInlining)] public T Or(Func factory) => HasValue ? _value : factory(); public override bool Equals([NotNullWhen(true)] object? obj) => obj is Option other && Equals(other); public bool Equals(Option other) => (HasValue == other.HasValue) && (!HasValue || EqualityComparer.Default.Equals(_value, other._value)); public override int GetHashCode() => HasValue ? EqualityComparer.Default.GetHashCode(_value) : 0; public override string ToString() => HasValue ? $"Some({_value})" : $"None<{typeof(T).Name}>()"; }