|
| 1 | +//===----------------------------------------------------------------------===// |
| 2 | +// |
| 3 | +// This source file is part of the Swift.org open source project |
| 4 | +// |
| 5 | +// Copyright (c) 2025 Apple Inc. and the Swift project authors |
| 6 | +// Licensed under Apache License v2.0 with Runtime Library Exception |
| 7 | +// |
| 8 | +// See https://swift.org/LICENSE.txt for license information |
| 9 | +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| 10 | +// |
| 11 | +//===----------------------------------------------------------------------===// |
| 12 | + |
| 13 | +@available(macOS 13, *) |
| 14 | +public typealias DispatchTime = ContinuousClock.Instant |
| 15 | + |
| 16 | +/// The very first time someone tries to reference a `uptimeNanoseconds` or a similar |
| 17 | +/// function that references a beginning point, this variable will be initialized as a beginning |
| 18 | +/// reference point. This guarantees that all calls to `uptimeNanoseconds` or similar |
| 19 | +/// will be 0 or greater. |
| 20 | +/// |
| 21 | +/// By design, it is not possible to related `ContinuousClock.Instant` to |
| 22 | +/// `ProcessInfo.processInfo.systemUptime`, and even if one devised such |
| 23 | +/// a mechanism, it would open the door for fingerprinting. It's best to let the concept |
| 24 | +/// of uptime be relative to previous uptime calls. |
| 25 | +@available(macOS 13, *) |
| 26 | +private let uptimeBeginning: DispatchTime = DispatchTime.now() |
| 27 | + |
| 28 | +@available(macOS 13, *) |
| 29 | +extension DispatchTime { |
| 30 | + public static func now() -> DispatchTime { |
| 31 | + now |
| 32 | + } |
| 33 | + |
| 34 | + public var uptimeNanoseconds: UInt64 { |
| 35 | + let beginning = uptimeBeginning |
| 36 | + let rightNow = DispatchTime.now() |
| 37 | + let uptimeDuration: Int64 = beginning.duration(to: rightNow).nanosecondsClamped |
| 38 | + guard uptimeDuration >= 0 else { |
| 39 | + assertionFailure("It shouldn't be possible to get a negative duration since uptimeBeginning.") |
| 40 | + return 0 |
| 41 | + } |
| 42 | + return UInt64(uptimeDuration) |
| 43 | + } |
| 44 | +} |
| 45 | + |
| 46 | +// NOTE: The following was copied from swift-nio/Source/NIOCore/TimeAmount+Duration on June 27, 2025 |
| 47 | +// It was copied rather than brought via dependencies to avoid introducing |
| 48 | +// a dependency on swift-nio for such a small piece of code. |
| 49 | +// |
| 50 | +// This library will need to have no depedendencies to be able to be integrated into GCD. |
| 51 | +@available(macOS 13, iOS 16, tvOS 16, watchOS 9, *) |
| 52 | +extension Swift.Duration { |
| 53 | + /// The duration represented as nanoseconds, clamped to maximum expressible value. |
| 54 | + fileprivate var nanosecondsClamped: Int64 { |
| 55 | + let components = self.components |
| 56 | + |
| 57 | + let secondsComponentNanos = components.seconds.multipliedReportingOverflow(by: 1_000_000_000) |
| 58 | + let attosCompononentNanos = components.attoseconds / 1_000_000_000 |
| 59 | + let combinedNanos = secondsComponentNanos.partialValue.addingReportingOverflow(attosCompononentNanos) |
| 60 | + |
| 61 | + guard |
| 62 | + !secondsComponentNanos.overflow, |
| 63 | + !combinedNanos.overflow |
| 64 | + else { |
| 65 | + return .max |
| 66 | + } |
| 67 | + |
| 68 | + return combinedNanos.partialValue |
| 69 | + } |
| 70 | +} |
0 commit comments