DotNext by .NET Foundation and Contributors

<PackageReference Include="DotNext" Version="5.0.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; 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; } } }