Refactored Option<T> to have opertator lifting and removed ref struct for now.
All checks were successful
Build NuGet / build (push) Successful in 1m43s

This commit is contained in:
2026-08-07 12:58:11 -04:00
parent 1d53af4b46
commit 262b76c4d5
13 changed files with 1123 additions and 262 deletions

View File

@@ -1,40 +1,104 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
// using System.Diagnostics;
// using System.Diagnostics.CodeAnalysis;
// using System.Runtime.CompilerServices;
// using SJK.Functional;
namespace SJK.Functional;
// namespace SJK.Functional
// {
// /// <summary>
// /// A simple implementation of a monadic option, which can hold either a value of type T or no value.
// /// </summary>
// 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);
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");
// /// <summary>
// /// A constructor for creating an instance of the Option struct.
// /// </summary>
// 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.");
// _value = value;
// HasValue = hasValue;
// }
// [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();
// /// <summary>
// /// Gets the held value if it exists. Throws an exception if there's no value.
// /// </summary>
// public T? Value => HasValue ? _value : throw new InvalidOperationException("Can not retrieve value when there is no value.");
public override bool Equals([NotNullWhen(true)] object? obj) => obj is Option<T> other && Equals(other);
// /// <summary>
// /// Applies a function to the held value if it exists, otherwise applies another function.
// /// </summary>
// /// <typeparam name="TResult">The type of result produced by the functions.</typeparam>
// public TResult Match<TResult>(Func<T, TResult> some, Func<TResult> none)
// {
// // If we have a value, apply 'some' to it. Otherwise, apply 'none'.
// return HasValue ? some(_value) : none();
// }
public bool Equals(Option<T> other) => (HasValue == other.HasValue) && (!HasValue || EqualityComparer<T>.Default.Equals(_value, other._value));
// /// <summary>
// /// Maps the held value if it exists using the given function, otherwise returns an empty option.
// /// </summary>
// /// <typeparam name="TResult">The type of result produced by the mapping function.</typeparam>
// public Option<TResult> Map<TResult>(Func<T, TResult> f)
// {
// // If we have a value, map it and wrap the result in another option. Otherwise, return an empty option.
// return HasValue ? Option<TResult>.Some(f(_value)) : Option<TResult>.None;
// }
public override int GetHashCode() => HasValue ? EqualityComparer<T>.Default.GetHashCode(_value) : 0;
public override string ToString() => HasValue ? $"Some({_value})" : $"None<{typeof(T).Name}>()";
}
// /// <summary>
// /// Binds the held value if it exists using the given function, otherwise returns an empty option.
// /// </summary>
// /// <typeparam name="TResult">The type of result produced by the binding function.</typeparam>
// public Option<TResult> Bind<TResult>(Func<T, Option<TResult>> f)
// {
// // If we have a value, bind it and wrap the result in another option. Otherwise, return an empty option.
// return HasValue ? f(_value) : Option<TResult>.None;
// }
// /// <summary>
// /// Returns the held value if it exists, otherwise returns a default value.
// /// </summary>
// public T OrDefault(T value)
// {
// // If we have a value, return it. Otherwise, return the default value.
// return HasValue ? _value : value;
// }
// /// <summary>
// /// Returns the held value if it exists, otherwise returns a result from a factory function.
// /// </summary>
// public T Or(Func<T> factory)
// {
// // If we have a value, return it. Otherwise, invoke the factory function and return its result.
// return HasValue ? _value : factory();
// }
// public override bool Equals([NotNullWhen(true)] object? obj) => obj is Option<T> other && Equals(other);
// /// <summary>
// /// Checks for equality with another option of type T.
// /// </summary>
// public bool Equals(Option<T> other)
// {
// // If both options have values, check their equality. Otherwise, consider them equal if they're both empty.
// return (HasValue == other.HasValue) && (!HasValue || EqualityComparer<T>.Default.Equals(_value, other._value));
// }
// public override int GetHashCode() => HasValue ? EqualityComparer<T>.Default.GetHashCode(_value) : 0;
// /// <summary>
// /// Returns a string representation of this option.
// /// </summary>
// public override string ToString()
// {
// // If we have a value, return it as a 'Some' with the value. Otherwise, return an empty 'None'.
// return HasValue ? $"Some({_value})" : $"None<{typeof(T).Name}>()";
// }
// }
// }