using System;
namespace Utils;
///
/// "Nullable" wrapper. Can wrap both value types and reference types.
///
///
public readonly struct Option : IEquatable>
{
public bool HasValue { get; } = false;
private readonly T _value = default!;
public Option() { }
public Option(T value)
{
_value = value;
HasValue = true;
}
public T Value
{
get {
if (!HasValue)
throw new InvalidOperationException("Cannot access value of None");
return _value;
}
}
public bool Equals(Option other)
{
return (!HasValue && !other.HasValue)
|| (HasValue && other.HasValue && _value!.Equals(other._value));
}
public override bool Equals(object obj)
{
if (obj is Option other)
return Equals(other);
return false;
}
public override int GetHashCode()
{
return HashCode.Combine(HasValue, _value);
}
public static bool operator ==(Option left, Option right)
{
return left.Equals(right);
}
public static bool operator !=(Option left, Option right)
{
return !(left == right);
}
public Option Map(Func map)
{
if (HasValue)
return Option.Some(map(_value));
return Option.None();
}
public T Or(T otherwise)
{
if (HasValue)
return _value;
return otherwise;
}
public Option Or(Option otherwise)
{
if (HasValue)
return this;
return otherwise;
}
}
public static class Option
{
public static Option None()
=> default;
public static Option Some(T value)
=> new(value);
public static Option FromNullable(T? value)
where T : struct
{
if (!value.HasValue)
return default;
return new(value.Value);
}
public static Option FromObject(T? value)
{
if (value is null)
return default;
return new(value);
}
}