Files
SjkScripts/Functional/OptionalStruct.cs
2026-04-04 13:18:04 -04:00

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