Optional<T>
public struct Optional<T> : IEquatable<Optional<T>>, IEquatable<T>, IStructuralEquatable, IOptionMonad<T, Optional<T>>, IOptionMonad<T>, ISupplier<object>, IFunctional<Func<object>>
A container object which may or may not contain a value.
using DotNext.Runtime.CompilerServices;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DotNext
{
[StructLayout(LayoutKind.Auto)]
[System.Runtime.CompilerServices.NullableContext(1)]
[System.Runtime.CompilerServices.Nullable(0)]
public readonly struct Optional<[System.Runtime.CompilerServices.Nullable(2)] T> : IEquatable<Optional<T>>, IEquatable<T>, IStructuralEquatable, IOptionMonad<T, Optional<T>>, IOptionMonad<T>, ISupplier<object>, IFunctional<Func<object>>
{
private const byte UndefinedValue = 0;
private const byte NullValue = 1;
private const byte NotEmptyValue = 3;
private static readonly bool IsOptional;
private readonly T value;
private readonly byte kind;
[System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public static Optional<T> None {
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
get {
return default(Optional<T>);
}
}
[MemberNotNullWhen(true, "value")]
public bool HasValue {
[MemberNotNullWhen(true, "value")]
get {
return kind == 3;
}
}
public bool IsUndefined => kind == 0;
public bool IsNull => kind == 1;
public T Value {
get {
Validate();
return value;
}
}
static Optional()
{
Type typeFromHandle = typeof(T);
IsOptional = (typeFromHandle.IsConstructedGenericType && typeFromHandle.GetGenericTypeDefinition() == typeof(Optional<>));
}
[System.Runtime.CompilerServices.NullableContext(2)]
public Optional(T value)
{
this.value = value;
kind = (byte)((value == null) ? 1 : (IsOptional ? GetKindUnsafe(ref value) : 3));
}
internal Optional([In] [IsReadOnly] ref Optional<Optional<T>> value)
{
this.value = value.value.value;
kind = value.kind;
}
private static byte GetKindUnsafe([DisallowNull] ref T optionalValue)
{
if (!optionalValue.Equals(null)) {
if (!optionalValue.Equals(Sentinel.Instance))
return 3;
return 0;
}
return 1;
}
[System.Runtime.CompilerServices.NullableContext(2)]
[EditorBrowsable(EditorBrowsableState.Advanced)]
public static bool IsValueDefined([NotNullWhen(true)] T value)
{
if (value != null) {
if (IsOptional)
return GetKindUnsafe(ref value) == 3;
return true;
}
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[return: IsReadOnly]
internal static ref T GetReference([In] [IsReadOnly] ref Optional<T> optional)
{
return ref optional.value;
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public Optional<object> Box()
{
if (!IsUndefined)
return new Optional<object>(value);
return default(Optional<object>);
}
public bool TryGet([MaybeNullWhen(false)] out T value)
{
value = this.value;
return HasValue;
}
public bool TryGet([MaybeNullWhen(false)] out T value, out bool isNull)
{
value = this.value;
switch (kind) {
default:
isNull = false;
return false;
case 1:
isNull = true;
return false;
case 3:
isNull = false;
return true;
}
}
[System.Runtime.CompilerServices.NullableContext(2)]
[return: NotNullIfNotNull("defaultValue")]
public T Or(T defaultValue)
{
if (!HasValue)
return defaultValue;
return value;
}
[return: NotNull]
public T OrThrow<[System.Runtime.CompilerServices.Nullable(0)] TException>() where TException : Exception, new
{
return OrThrow(default(Activator<TException>));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[return: NotNull]
private T OrThrow<TFactory>(TFactory exceptionFactory) where TFactory : struct, ISupplier<Exception>
{
Validate(exceptionFactory);
return this.value;
}
[MemberNotNull("value")]
internal void Validate<TFactory>(TFactory exceptionFactory) where TFactory : struct, ISupplier<Exception>
{
if (!this.HasValue)
<Validate>g__Throw|26_0(exceptionFactory);
}
[return: NotNull]
public T OrThrow(Func<Exception> exceptionFactory)
{
return OrThrow((DelegatingSupplier<Exception>)exceptionFactory);
}
[CLSCompliant(false)]
[return: NotNull]
public T OrThrow([System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] IntPtr exceptionFactory)
{
return OrThrow((Supplier<Exception>)(long)exceptionFactory);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private T OrInvoke<TSupplier>(TSupplier defaultFunc) where TSupplier : struct, ISupplier<T>
{
if (!this.HasValue)
return ((ISupplier<T>)defaultFunc).Invoke();
return this.value;
}
public T OrInvoke(Func<T> defaultFunc)
{
return OrInvoke((DelegatingSupplier<T>)defaultFunc);
}
[CLSCompliant(false)]
public T OrInvoke([System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] IntPtr defaultFunc)
{
return OrInvoke((Supplier<T>)(long)defaultFunc);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public T OrDefault()
{
return value;
}
[MemberNotNull("value")]
internal void Validate()
{
byte b = kind;
if (b != 3)
<Validate>g__Throw|35_0(b == 0);
}
object ISupplier<object>.Invoke()
{
if (!HasValue)
return null;
return value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Optional<TResult> Convert<TResult, TConverter>(TConverter converter) where TConverter : struct, ISupplier<T, TResult>
{
if (!this.HasValue)
return Optional<TResult>.None;
return ((ISupplier<T, TResult>)converter).Invoke(this.value);
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public Optional<TResult> Convert<[System.Runtime.CompilerServices.Nullable(2)] TResult>(Converter<T, TResult> mapper)
{
return Convert<TResult, DelegatingConverter<T, TResult>>(mapper);
}
[System.Runtime.CompilerServices.NullableContext(2)]
[CLSCompliant(false)]
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public Optional<TResult> Convert<TResult>([System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1,
1
})] IntPtr mapper)
{
return Convert<TResult, Supplier<T, TResult>>(mapper);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Optional<TResult> ConvertOptional<TResult, TConverter>(TConverter converter) where TConverter : struct, ISupplier<T, Optional<TResult>>
{
if (!this.HasValue)
return Optional<TResult>.None;
return ((ISupplier<T, Optional<TResult>>)converter).Invoke(this.value);
}
[System.Runtime.CompilerServices.NullableContext(2)]
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public Optional<TResult> Convert<TResult>([System.Runtime.CompilerServices.Nullable(new byte[] {
1,
1,
0,
1
})] Converter<T, Optional<TResult>> mapper)
{
return ConvertOptional<TResult, DelegatingConverter<T, Optional<TResult>>>(mapper);
}
[System.Runtime.CompilerServices.NullableContext(2)]
[CLSCompliant(false)]
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public Optional<TResult> Convert<TResult>([System.Runtime.CompilerServices.Nullable(new byte[] {
0,
0,
1,
1
})] IntPtr mapper)
{
return ConvertOptional<TResult, Supplier<T, Optional<TResult>>>(mapper);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Optional<T> If<TPredicate>(TPredicate condition) where TPredicate : struct, ISupplier<T, bool>
{
if (!this.HasValue || !((ISupplier<T, bool>)condition).Invoke(this.value))
return Optional<T>.None;
return this;
}
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public Optional<T> If(Predicate<T> condition)
{
return If((DelegatingPredicate<T>)condition);
}
[CLSCompliant(false)]
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
public Optional<T> If([System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] IntPtr condition)
{
return If((Supplier<T, bool>)(long)condition);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public override string ToString()
{
switch (kind) {
case 0:
return "<Undefined>";
case 1:
return "<Null>";
default:
return value.ToString();
}
}
public override int GetHashCode()
{
switch (kind) {
case 0:
return 0;
case 1:
return 1;
default:
return EqualityComparer<T>.Default.GetHashCode(value);
}
}
[System.Runtime.CompilerServices.NullableContext(2)]
public bool Equals(T other)
{
if (!IsUndefined)
return EqualityComparer<T>.Default.Equals(value, other);
return false;
}
private bool Equals([In] [IsReadOnly] ref Optional<T> other)
{
if (kind == other.kind) {
byte b = kind;
if (b != 0 && b != 1)
return EqualityComparer<T>.Default.Equals(value, other.value);
return true;
}
return false;
}
public bool Equals([System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] Optional<T> other)
{
return Equals(ref other);
}
[System.Runtime.CompilerServices.NullableContext(2)]
public override bool Equals(object other)
{
if (other == null)
return IsNull;
if (!(other is Optional<T>)) {
if (!(other is T))
return other == Sentinel.Instance && IsUndefined;
T other2 = (T)other;
return Equals(other2);
}
Optional<T> other3 = (Optional<T>)other;
return Equals(ref other3);
}
public bool Equals([System.Runtime.CompilerServices.Nullable(2)] object other, IEqualityComparer comparer)
{
if (!IsUndefined)
return comparer.Equals(value, other);
return false;
}
public int GetHashCode(IEqualityComparer comparer)
{
switch (kind) {
case 0:
return 0;
case 1:
return 1;
default:
return comparer.GetHashCode(value);
}
}
public static implicit operator Optional<T>(T value)
{
return new Optional<T>(value);
}
Optional<T> IOptionMonad<!0, Optional<!0>>.op_Implicit(T value)
{
return this.op_Implicit(value);
}
public static explicit operator T([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> optional)
{
return optional.Value;
}
T IOptionMonad<!0, Optional<!0>>.op_Explicit([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> optional)
{
return this.op_Explicit(ref optional);
}
public static bool operator ==([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> first, [In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> second)
{
return first.Equals(ref second);
}
public static bool operator !=([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> first, [In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> second)
{
return !first.Equals(ref second);
}
public static Optional<T>operator |([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> first, [In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> second)
{
if (!first.HasValue)
return second;
return first;
}
public static Optional<T>operator ^([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> first, [In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> second)
{
int num = first.kind - second.kind;
if ((uint)(num - -3) <= 2)
return second;
if ((uint)(num - 1) <= 2)
return first;
return None;
}
public static bool operator true([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> optional)
{
return optional.HasValue;
}
bool IOptionMonad<!0, Optional<!0>>.op_True([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> optional)
{
return this.op_True(ref optional);
}
public static bool operator false([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> optional)
{
return optional.kind < 3;
}
bool IOptionMonad<!0, Optional<!0>>.op_False([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> optional)
{
return this.op_False(ref optional);
}
}
}