You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
5.5 KiB
221 lines
5.5 KiB
// Needed for NET40 |
|
#if !NET_4_6 |
|
using System; |
|
|
|
namespace LinqInternal.Threading.Needles |
|
{ |
|
[Serializable] |
|
[System.Diagnostics.DebuggerNonUserCode] |
|
internal class Needle<T> : IEquatable<Needle<T>>, IRecyclableNeedle<T>, IPromise<T> |
|
{ |
|
private readonly int _hashCode; |
|
private INeedle<T> _target; // Can be null - set in SetTargetValue and SetTargetError |
|
|
|
public Needle() |
|
{ |
|
_target = null; |
|
_hashCode = base.GetHashCode(); |
|
} |
|
|
|
public Needle(T target) |
|
{ |
|
if (ReferenceEquals(target, null)) |
|
{ |
|
_target = null; |
|
_hashCode = base.GetHashCode(); |
|
} |
|
else |
|
{ |
|
_target = new StructNeedle<T>(target); |
|
_hashCode = target.GetHashCode(); |
|
} |
|
} |
|
|
|
public Exception Exception |
|
{ |
|
get |
|
{ |
|
var target = _target; |
|
if (target is ExceptionStructNeedle<T>) |
|
{ |
|
return ((ExceptionStructNeedle<T>)target).Exception; |
|
} |
|
return null; |
|
} |
|
} |
|
|
|
bool IPromise.IsCanceled |
|
{ |
|
get { return false; } |
|
} |
|
|
|
bool IPromise.IsCompleted |
|
{ |
|
get { return IsAlive; } |
|
} |
|
|
|
public bool IsAlive |
|
{ |
|
get |
|
{ |
|
var target = _target; |
|
return target != null && target.IsAlive; |
|
} |
|
} |
|
|
|
public bool IsFaulted |
|
{ |
|
get { return _target is ExceptionStructNeedle<T>; } |
|
} |
|
|
|
public virtual T Value |
|
{ |
|
get { return _target.Value; } |
|
|
|
set { SetTargetValue(value); } |
|
} |
|
|
|
public static explicit operator T(Needle<T> needle) |
|
{ |
|
if (needle == null) |
|
{ |
|
throw new ArgumentNullException("needle"); |
|
} |
|
return needle.Value; |
|
} |
|
|
|
public static implicit operator Needle<T>(T field) |
|
{ |
|
return new Needle<T>(field); |
|
} |
|
|
|
public static bool operator !=(Needle<T> left, Needle<T> right) |
|
{ |
|
return NotEqualsExtracted(left, right); |
|
} |
|
|
|
public static bool operator ==(Needle<T> left, Needle<T> right) |
|
{ |
|
return EqualsExtracted(left, right); |
|
} |
|
|
|
public override bool Equals(object obj) |
|
{ |
|
var needle = obj as Needle<T>; |
|
if (needle != null) |
|
{ |
|
return EqualsExtracted(this, needle); |
|
} |
|
var target = _target; |
|
if (_target == null) |
|
{ |
|
return obj == null; |
|
} |
|
if (obj == null) |
|
{ |
|
return false; |
|
} |
|
return target.Equals(obj); |
|
} |
|
|
|
public bool Equals(Needle<T> other) |
|
{ |
|
var target = _target; |
|
if (target == null) |
|
{ |
|
return other._target == null; |
|
} |
|
return EqualsExtracted(this, other); |
|
} |
|
|
|
public virtual void Free() |
|
{ |
|
_target = null; |
|
} |
|
|
|
public override int GetHashCode() |
|
{ |
|
return _hashCode; |
|
} |
|
|
|
public override string ToString() |
|
{ |
|
var target = Value; |
|
if (IsAlive) |
|
{ |
|
return target.ToString(); |
|
} |
|
return "<Dead Needle>"; |
|
} |
|
|
|
protected void SetTargetError(Exception error) |
|
{ |
|
_target = new ExceptionStructNeedle<T>(error); |
|
} |
|
|
|
protected void SetTargetValue(T value) |
|
{ |
|
if (_target is StructNeedle<T>) |
|
{ |
|
// This may throw NotSupportedException if SetTargetError has just executed |
|
try |
|
{ |
|
_target.Value = value; |
|
return; |
|
} |
|
catch (NotSupportedException) |
|
{ |
|
// preventing return |
|
} |
|
} |
|
_target = new StructNeedle<T>(value); |
|
} |
|
|
|
private static bool EqualsExtracted(Needle<T> left, Needle<T> right) |
|
{ |
|
if (ReferenceEquals(left, null)) |
|
{ |
|
return ReferenceEquals(right, null); |
|
} |
|
if (ReferenceEquals(right, null)) |
|
{ |
|
return false; |
|
} |
|
var leftTarget = left._target; |
|
var rightTarget = right._target; |
|
if (leftTarget == null) |
|
{ |
|
return rightTarget == null; |
|
} |
|
if (rightTarget == null) |
|
{ |
|
return false; |
|
} |
|
return leftTarget.Equals(rightTarget); |
|
} |
|
|
|
private static bool NotEqualsExtracted(Needle<T> left, Needle<T> right) |
|
{ |
|
if (ReferenceEquals(left, null)) |
|
{ |
|
return !ReferenceEquals(right, null); |
|
} |
|
if (ReferenceEquals(right, null)) |
|
{ |
|
return true; |
|
} |
|
var leftTarget = left._target; |
|
var rightTarget = right._target; |
|
if (leftTarget == null) |
|
{ |
|
return rightTarget != null; |
|
} |
|
if (rightTarget == null) |
|
{ |
|
return true; |
|
} |
|
return !leftTarget.Equals(rightTarget); |
|
} |
|
} |
|
} |
|
#endif |