Skip to content

Commit 13ea1fe

Browse files
authored
Introducing Timer.record(_ duration:), closes #114 (#133)
Motivation: `Duration` is available starting Swift 5.7, and we should probably support it in our convinience API. Modifications: - Timer.record(_ duration: Duration) implementation - A unit test case - Generated Linux tests
1 parent 971ba26 commit 13ea1fe

File tree

4 files changed

+65
-0
lines changed

4 files changed

+65
-0
lines changed

Sources/Metrics/Metrics.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,29 @@ extension Timer {
7474
}
7575
}
7676
}
77+
78+
#if swift(>=5.7)
79+
extension Timer {
80+
/// Convenience for recording a duration based on ``Duration``.
81+
///
82+
/// `Duration` will be converted to an `Int64` number of nanoseconds, and then recorded with nanosecond precision.
83+
///
84+
/// - Parameters:
85+
/// - duration: The `Duration` to record.
86+
///
87+
/// - Throws: `TimerError.durationToIntOverflow` if conversion from `Duration` to `Int64` of Nanoseconds overflowed.
88+
@available(macOS 13, iOS 16, tvOS 15, watchOS 8, *)
89+
@inlinable
90+
public func record(_ duration: Duration) {
91+
// `Duration` doesn't have a nice way to convert it nanoseconds or seconds,
92+
// and manual conversion can overflow.
93+
let seconds = duration.components.seconds.multipliedReportingOverflow(by: 1_000_000_000)
94+
guard !seconds.overflow else { return self.recordNanoseconds(Int64.max) }
95+
96+
let nanoseconds = seconds.partialValue.addingReportingOverflow(duration.components.attoseconds / 1_000_000_000)
97+
guard !nanoseconds.overflow else { return self.recordNanoseconds(Int64.max) }
98+
99+
self.recordNanoseconds(nanoseconds.partialValue)
100+
}
101+
}
102+
#endif

Tests/MetricsTests/MetricsTests+XCTest.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ extension MetricsExtensionsTests {
2929
("testTimerWithTimeInterval", testTimerWithTimeInterval),
3030
("testTimerWithDispatchTime", testTimerWithDispatchTime),
3131
("testTimerWithDispatchTimeInterval", testTimerWithDispatchTimeInterval),
32+
("testTimerDuration", testTimerDuration),
3233
("testTimerUnits", testTimerUnits),
3334
("testPreferDisplayUnit", testPreferDisplayUnit),
3435
]

Tests/MetricsTests/MetricsTests.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,38 @@ class MetricsExtensionsTests: XCTestCase {
9696
XCTAssertEqual(metrics.timers.count, 1, "timer should have been stored")
9797
}
9898

99+
func testTimerDuration() throws {
100+
// Wrapping only the insides of the test case so that the generated
101+
// tests on Linux in MetricsTests+XCTest don't complain that the func does not exist.
102+
#if swift(>=5.7)
103+
guard #available(iOS 16, macOS 13, tvOS 15, watchOS 8, *) else {
104+
throw XCTSkip("Timer.record(_ duration: Duration) is not available on this platform")
105+
}
106+
107+
let metrics = TestMetrics()
108+
MetricsSystem.bootstrapInternal(metrics)
109+
110+
let name = "timer-\(UUID().uuidString)"
111+
let timer = Timer(label: name)
112+
113+
let duration = Duration(secondsComponent: 3, attosecondsComponent: 123_000_000_000_000_000)
114+
let nanoseconds = duration.components.seconds * 1_000_000_000 + duration.components.attoseconds / 1_000_000_000
115+
timer.record(duration)
116+
117+
// Record a Duration that would overflow,
118+
// expect Int64.max to be recorded.
119+
timer.record(Duration(secondsComponent: 10_000_000_000, attosecondsComponent: 123))
120+
121+
let testTimer = try metrics.expectTimer(timer)
122+
XCTAssertEqual(testTimer.values.count, 2, "expected number of entries to match")
123+
XCTAssertEqual(testTimer.values.first, nanoseconds, "expected value to match")
124+
XCTAssertEqual(testTimer.values[1], Int64.max, "expected to record Int64.max if Durataion overflows")
125+
XCTAssertEqual(metrics.timers.count, 1, "timer should have been stored")
126+
#elseif swift(>=5.2)
127+
throw XCTSkip("Timer.record(_ duration: Duration) is only available on Swift >=5.7")
128+
#endif
129+
}
130+
99131
func testTimerUnits() throws {
100132
let metrics = TestMetrics()
101133
MetricsSystem.bootstrapInternal(metrics)

scripts/soundness.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ fi
6464
printf "\033[0;32mokay.\033[0m\n"
6565

6666
printf "=> Checking format... "
67+
68+
if [[ ! -x $(which swiftformat) ]]; then
69+
printf "\033[0;31mswiftformat not found!\033[0m\n"
70+
exit 1
71+
fi
72+
6773
FIRST_OUT="$(git status --porcelain)"
6874
swiftformat . > /dev/null 2>&1
6975
SECOND_OUT="$(git status --porcelain)"

0 commit comments

Comments
 (0)