Optional<T>
A container object which may or may not contain a value.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Reflection;
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
{
private const byte UndefinedValue = 0;
private const byte NullValue = 1;
private const byte NotEmptyValue = 3;
private static readonly bool IsOptional;
[System.Runtime.CompilerServices.Nullable(2)]
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 {
string message;
switch (kind) {
default:
return value;
case 0:
message = ExceptionMessages.OptionalNoValue;
break;
case 1:
message = ExceptionMessages.OptionalNullValue;
break;
}
throw new InvalidOperationException(message);
}
}
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 ? <.ctor>g__GetKindUnsafe|7_0(ref value) : 3));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[System.Runtime.CompilerServices.NullableContext(2)]
[return: IsReadOnly]
internal static ref T GetReference([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] 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)]
[System.Runtime.CompilerServices.NullableContext(0)]
[return: System.Runtime.CompilerServices.Nullable(1)]
[return: NotNull]
private T OrThrow<TFactory>(TFactory exceptionFactory) where TFactory : struct, ISupplier<Exception>
{
if (!this.HasValue)
throw ((ISupplier<Exception>)exceptionFactory).Invoke();
return this.value;
}
[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)]
[System.Runtime.CompilerServices.NullableContext(0)]
[return: System.Runtime.CompilerServices.Nullable(1)]
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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[System.Runtime.CompilerServices.NullableContext(0)]
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
private Optional<TResult> Convert<[System.Runtime.CompilerServices.Nullable(2)] 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)]
[System.Runtime.CompilerServices.NullableContext(0)]
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
private Optional<TResult> ConvertOptional<[System.Runtime.CompilerServices.Nullable(2)] 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)]
[System.Runtime.CompilerServices.NullableContext(0)]
[return: System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})]
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] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> other)
{
if (kind != other.kind)
return false;
byte b = kind;
if ((uint)b > 1)
return EqualityComparer<T>.Default.Equals(value, other.value);
return true;
}
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 == Missing.Value && 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);
}
public static explicit operator T([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> optional)
{
return optional.Value;
}
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;
}
public static bool operator false([In] [IsReadOnly] [System.Runtime.CompilerServices.Nullable(new byte[] {
0,
1
})] ref Optional<T> optional)
{
return optional.kind < 3;
}
}
}