Timeout
Helps to compute timeout for asynchronous operations.
using DotNext.Diagnostics;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DotNext.Threading
{
[StructLayout(LayoutKind.Auto)]
public readonly struct Timeout
{
public const long InfiniteTicks = -10000;
private readonly Timestamp created;
private readonly TimeSpan timeout;
public static Timeout Infinite => default(Timeout);
public static Timeout Expired { get; } = new Timeout(TimeSpan.Zero);
public TimeSpan Value {
get {
if (!IsInfinite)
return timeout;
return new TimeSpan(-10000);
}
}
public bool IsInfinite => created.IsEmpty;
public bool IsExpired {
get {
if (!IsInfinite)
return created.Elapsed > timeout;
return false;
}
}
public Timeout(TimeSpan timeout)
{
long ticks = timeout.Ticks;
if (ticks < 0) {
if (ticks != -10000)
throw new ArgumentOutOfRangeException("timeout");
this = default(Timeout);
} else {
created = new Timestamp();
this.timeout = timeout;
}
}
public void ThrowIfExpired()
{
if (IsExpired)
throw new TimeoutException();
}
public void ThrowIfExpired(out TimeSpan remainingTime)
{
if (!TryGetRemainingTime(out remainingTime))
throw new TimeoutException();
}
public bool TryGetRemainingTime(out TimeSpan remainingTime)
{
if (IsInfinite) {
remainingTime = new TimeSpan(-10000);
return true;
}
return (remainingTime = timeout - created.Elapsed) >= TimeSpan.Zero;
}
public static bool operator true([In] [IsReadOnly] ref Timeout timeout)
{
return timeout.IsExpired;
}
public static bool operator false([In] [IsReadOnly] ref Timeout timeout)
{
return !timeout.IsExpired;
}
public static implicit operator TimeSpan([In] [IsReadOnly] ref Timeout timeout)
{
return timeout.Value;
}
}
}