Timeout
Helps to compute timeout for asynchronous operations.
using DotNext.Diagnostics;
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
namespace DotNext.Threading
{
[StructLayout(LayoutKind.Auto)]
public readonly struct Timeout
{
private readonly Timestamp created;
private readonly TimeSpan? timeout;
public TimeSpan Value => timeout ?? System.Threading.Timeout.InfiniteTimeSpan;
public bool IsInfinite => !timeout.HasValue;
public bool IsExpired {
get {
if (timeout.TryGetValue(out TimeSpan value))
return created.Elapsed > value;
return false;
}
}
public TimeSpan? RemainingTime {
get {
if (timeout.TryGetValue(out TimeSpan value)) {
value -= created.Elapsed;
if (!(value >= TimeSpan.Zero))
return null;
return value;
}
return System.Threading.Timeout.InfiniteTimeSpan;
}
}
public Timeout(TimeSpan timeout)
{
created = Timestamp.Current;
if (timeout == System.Threading.Timeout.InfiniteTimeSpan)
this.timeout = null;
else {
if (timeout < TimeSpan.Zero)
throw new ArgumentOutOfRangeException("timeout");
this.timeout = timeout;
}
}
public void ThrowIfExpired()
{
if (IsExpired)
throw new TimeoutException();
}
public void ThrowIfExpired(out TimeSpan remaining)
{
if (!RemainingTime.TryGetValue(out remaining))
throw new TimeoutException();
}
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;
}
}
}