DotNext by .NET Foundation and Contributors

<PackageReference Include="DotNext" Version="4.7.1" />

 Timeout

public struct 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 static Timeout Infinite => default(Timeout); public static Timeout Expired { get; } = new Timeout(TimeSpan.Zero); public TimeSpan Value { get { if (!IsInfinite) return timeout; return System.Threading.Timeout.InfiniteTimeSpan; } } public bool IsInfinite => created.IsEmpty; public bool IsExpired { get { if (!IsInfinite) return created.Elapsed > timeout; return false; } } public TimeSpan? RemainingTime { get { if (!IsInfinite) { TimeSpan value; if (!((value = timeout - created.Elapsed) >= TimeSpan.Zero)) return null; return value; } return System.Threading.Timeout.InfiniteTimeSpan; } } public Timeout(TimeSpan timeout) { if (timeout == System.Threading.Timeout.InfiniteTimeSpan) this = default(Timeout); else { if (timeout < TimeSpan.Zero) throw new ArgumentOutOfRangeException("timeout"); created = new Timestamp(); this.timeout = timeout; } } public void ThrowIfExpired() { if (IsExpired) throw new TimeoutException(); } public void ThrowIfExpired(out TimeSpan remaining) { if (IsInfinite) remaining = System.Threading.Timeout.InfiniteTimeSpan; else if ((remaining = timeout - created.Elapsed) < TimeSpan.Zero) { 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; } } }