/******************************************************************************
* Copyright (C) Ultraleap, Inc. 2011-2021. *
* *
* Use subject to the terms of the Apache License 2.0 available at *
* http://www.apache.org/licenses/LICENSE-2.0, or another agreement *
* between Ultraleap and you, your company or other organization. *
******************************************************************************/
using System;
namespace Leap.Unity
{
///
/// A data structure that represents either a value of type A or
/// a value of type B. The value can never be both A and B.
/// Neither A nor B can ever be null.
///
public struct Either : IEquatable>, IComparable, IComparable>
{
///
/// Returns whether or not this Either contains the first value.
///
public readonly bool isA;
///
/// Returns whether or not this Either contains the second value.
///
public bool isB
{
get
{
return !isA;
}
}
private readonly A _a;
private readonly B _b;
///
/// Returns a Maybe that contains the value of A if it exists,
/// or no value if it doesn't.
///
public Maybe a
{
get
{
if (isA)
{
return Maybe.Some(_a);
}
else
{
return Maybe.None;
}
}
}
///
/// Returns a Maybe that contains the value of B if it exists,
/// or no value if it doesn't.
///
public Maybe b
{
get
{
if (isA)
{
return Maybe.None;
}
else
{
return Maybe.Some(_b);
}
}
}
///
/// Constructs an Either with a value of A.
///
public Either(A a)
{
if (a == null)
{
throw new ArgumentNullException("Cannot initialize an Either with a null value.");
}
isA = true;
_a = a;
_b = default(B);
}
///
/// Constructs an Either with a value of B.
///
public Either(B b)
{
if (b == null)
{
throw new ArgumentNullException("Cannot initialize an Either with a null value.");
}
isA = false;
_b = b;
_a = default(A);
}
///
/// Calls the first delegate with the value of A if it is present,
/// else calls the second delegate with the value of B.
///
public void Match(Action ifA, Action ifB)
{
if (isA)
{
if (ifA != null) ifA(_a);
}
else
{
if (ifB != null) ifB(_b);
}
}
///
/// If this either contains the value of A, the out argument is filled with
/// that value and this method returns true, else it returns false.
///
public bool TryGetA(out A a)
{
a = _a;
return isA;
}
///
/// If this either contains the value of B, the out argument is filled with
/// that value and this method returns true, else it returns false.
///
public bool TryGetB(out B b)
{
b = _b;
return !isA;
}
public override int GetHashCode()
{
if (isA)
{
return _a.GetHashCode();
}
else
{
return _b.GetHashCode();
}
}
public override bool Equals(object obj)
{
if (obj is Either)
{
return Equals((Either)obj);
}
else
{
return false;
}
}
public bool Equals(Either other)
{
if (isA != other.isA)
{
return false;
}
else if (isA)
{
return _a.Equals(other._a);
}
else
{
return _b.Equals(other._b);
}
}
public int CompareTo(object obj)
{
if (!(obj is Either))
{
throw new ArgumentException();
}
else
{
return CompareTo((Either)obj);
}
}
public int CompareTo(Either other)
{
if (isA != other.isA)
{
return isA ? -1 : 1;
}
else if (isA)
{
IComparable ca = _a as IComparable;
if (ca != null)
{
return ca.CompareTo(other._a);
}
else
{
IComparable c = _a as IComparable;
if (c != null)
{
return c.CompareTo(other._b);
}
else
{
return 0;
}
}
}
else
{
IComparable cb = _b as IComparable;
if (cb != null)
{
return cb.CompareTo(other._b);
}
else
{
IComparable c = _b as IComparable;
if (c != null)
{
return c.CompareTo(other._b);
}
else
{
return 0;
}
}
}
}
public static bool operator ==(Either either0, Either either1)
{
return either0.Equals(either1);
}
public static bool operator !=(Either either0, Either either1)
{
return !either0.Equals(either1);
}
public static bool operator >(Either either0, Either either1)
{
return either0.CompareTo(either1) > 0;
}
public static bool operator >=(Either either0, Either either1)
{
return either0.CompareTo(either1) >= 0;
}
public static bool operator <(Either either0, Either either1)
{
return either0.CompareTo(either1) < 0;
}
public static bool operator <=(Either either0, Either either1)
{
return either0.CompareTo(either1) <= 0;
}
public static implicit operator Either(A a)
{
return new Either(a);
}
public static implicit operator Either(B b)
{
return new Either(b);
}
}
}