41 lines
2.0 KiB
C#
41 lines
2.0 KiB
C#
|
|
using System.Diagnostics;
|
||
|
|
using System.Diagnostics.CodeAnalysis;
|
||
|
|
using System.Runtime.CompilerServices;
|
||
|
|
|
||
|
|
namespace SJK.Functional;
|
||
|
|
|
||
|
|
public struct Option<T> : IEquatable<Option<T>>
|
||
|
|
{
|
||
|
|
private readonly T? _value;
|
||
|
|
[MemberNotNullWhen(true, nameof(_value))]
|
||
|
|
public bool HasValue { get; }
|
||
|
|
public static Option<T> None => new(default, false);
|
||
|
|
public static Option<T> 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<TResult>(Func<T, TResult> some, Func<TResult> none) => HasValue ? some(_value) : none();
|
||
|
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
|
public Option<TResult> Map<TResult>(Func<T, TResult> f) => HasValue ? Option<TResult>.Some(f(_value)) : Option<TResult>.None;
|
||
|
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
|
public Option<TResult> Bind<TResult>(Func<T, Option<TResult>> f) => HasValue ? f(_value) : Option<TResult>.None;
|
||
|
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
|
public T OrDefault(T value) => HasValue ? _value : value;
|
||
|
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||
|
|
public T Or(Func<T> factory) => HasValue ? _value : factory();
|
||
|
|
|
||
|
|
public override bool Equals([NotNullWhen(true)] object? obj) => obj is Option<T> other && Equals(other);
|
||
|
|
|
||
|
|
public bool Equals(Option<T> other) => (HasValue == other.HasValue) && (!HasValue || EqualityComparer<T>.Default.Equals(_value, other._value));
|
||
|
|
|
||
|
|
public override int GetHashCode() => HasValue ? EqualityComparer<T>.Default.GetHashCode(_value) : 0;
|
||
|
|
public override string ToString() => HasValue ? $"Some({_value})" : $"None<{typeof(T).Name}>()";
|
||
|
|
}
|