Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add conversion between NimbleTimeInterval and the relatively new Duration API #1058

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Nimble.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,10 @@
89EEF5C12A06211D00988224 /* AsyncHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EEF5BB2A06210D00988224 /* AsyncHelpers.swift */; };
89EEF5C22A06211E00988224 /* AsyncHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EEF5BB2A06210D00988224 /* AsyncHelpers.swift */; };
89EEF5C32A06211F00988224 /* AsyncHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EEF5BB2A06210D00988224 /* AsyncHelpers.swift */; };
89EEF6102A23E7C000988224 /* NimbleTimeIntervalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EEF60F2A23E7C000988224 /* NimbleTimeIntervalTests.swift */; };
89EEF6112A23E7C000988224 /* NimbleTimeIntervalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EEF60F2A23E7C000988224 /* NimbleTimeIntervalTests.swift */; };
89EEF6122A23E7C000988224 /* NimbleTimeIntervalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EEF60F2A23E7C000988224 /* NimbleTimeIntervalTests.swift */; };
89EEF6132A23E7C000988224 /* NimbleTimeIntervalTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89EEF60F2A23E7C000988224 /* NimbleTimeIntervalTests.swift */; };
89F5E06D290765BB001F9377 /* PollingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F5E06C290765BB001F9377 /* PollingTest.swift */; };
89F5E06E290765BB001F9377 /* PollingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F5E06C290765BB001F9377 /* PollingTest.swift */; };
89F5E06F290765BB001F9377 /* PollingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89F5E06C290765BB001F9377 /* PollingTest.swift */; };
Expand Down Expand Up @@ -793,6 +797,7 @@
89EEF5A42A03293100988224 /* AsyncPredicate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncPredicate.swift; sourceTree = "<group>"; };
89EEF5B22A032C2500988224 /* AsyncPredicateTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncPredicateTest.swift; sourceTree = "<group>"; };
89EEF5BB2A06210D00988224 /* AsyncHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncHelpers.swift; sourceTree = "<group>"; };
89EEF60F2A23E7C000988224 /* NimbleTimeIntervalTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NimbleTimeIntervalTests.swift; sourceTree = "<group>"; };
89F5E06C290765BB001F9377 /* PollingTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PollingTest.swift; sourceTree = "<group>"; };
89F5E0852908E655001F9377 /* Polling+AsyncAwait.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Polling+AsyncAwait.swift"; sourceTree = "<group>"; };
89F5E08B290B8D22001F9377 /* AsyncAwait.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AsyncAwait.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -991,6 +996,7 @@
isa = PBXGroup;
children = (
CDC157902511957100EAA480 /* DSLTest.swift */,
89EEF60F2A23E7C000988224 /* NimbleTimeIntervalTests.swift */,
89F5E096290C37B8001F9377 /* OnFailureThrowsTest.swift */,
89F5E06C290765BB001F9377 /* PollingTest.swift */,
CDBC39B82462EA7D00069677 /* PredicateTest.swift */,
Expand Down Expand Up @@ -1752,6 +1758,7 @@
1F4A56701A3B319F009E1637 /* ObjCBeCloseToTest.m in Sources */,
1F4A56971A3B34AA009E1637 /* ObjCEndWithTest.m in Sources */,
1F4A567C1A3B3311009E1637 /* ObjCBeIdenticalToTest.m in Sources */,
89EEF6112A23E7C000988224 /* NimbleTimeIntervalTests.swift in Sources */,
965B0D0C1B62C06D0005AE66 /* UserDescriptionTest.swift in Sources */,
1FCF914F1C61C85A00B15DCB /* PostNotificationTest.swift in Sources */,
965B0D091B62B8ED0005AE66 /* ObjCUserDescriptionTest.m in Sources */,
Expand Down Expand Up @@ -1910,6 +1917,7 @@
1FCF91511C61C85A00B15DCB /* PostNotificationTest.swift in Sources */,
CD79C9B51D2CC848004B6F9A /* ObjCUserDescriptionTest.m in Sources */,
1F5DF19C1BDCA10200C3A531 /* BeginWithTest.swift in Sources */,
89EEF6122A23E7C000988224 /* NimbleTimeIntervalTests.swift in Sources */,
89F5E099290C37B8001F9377 /* StatusTest.swift in Sources */,
1F5DF1A01BDCA10200C3A531 /* BeIdenticalToTest.swift in Sources */,
1F5DF19A1BDCA10200C3A531 /* BeCloseToTest.swift in Sources */,
Expand Down Expand Up @@ -2073,6 +2081,7 @@
7A6AB2C21E7F547E00A2F694 /* ToSucceedTest.swift in Sources */,
A8A3B706207368EF00E25A08 /* ObjCSatisfyAllOfTest.m in Sources */,
1F4A56711A3B319F009E1637 /* ObjCBeCloseToTest.m in Sources */,
89EEF6102A23E7C000988224 /* NimbleTimeIntervalTests.swift in Sources */,
1F4A56981A3B34AA009E1637 /* ObjCEndWithTest.m in Sources */,
1F4A567D1A3B3311009E1637 /* ObjCBeIdenticalToTest.m in Sources */,
965B0D0D1B62C06D0005AE66 /* UserDescriptionTest.swift in Sources */,
Expand Down Expand Up @@ -2231,6 +2240,7 @@
D95F8932267EA1E8004B1B4D /* BeGreaterThanOrEqualToTest.swift in Sources */,
891364A029E695F300AD535E /* ObjCHaveCountTest.m in Sources */,
891364A529E695F300AD535E /* ObjCBeginWithTest.m in Sources */,
89EEF6132A23E7C000988224 /* NimbleTimeIntervalTests.swift in Sources */,
D95F8950267EA1E8004B1B4D /* BeIdenticalToTest.swift in Sources */,
D95F8942267EA1E8004B1B4D /* BeAKindOfTest.swift in Sources */,
D95F8947267EA1E8004B1B4D /* BeGreaterThanTest.swift in Sources */,
Expand Down
101 changes: 79 additions & 22 deletions Sources/Nimble/Utils/NimbleTimeInterval.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,3 @@
#if !os(WASI)

import Dispatch

#if canImport(CDispatch)
import CDispatch
#endif

/// A reimplementation of `DispatchTimeInterval` without the `never` case, and conforming to `Sendable`.
public enum NimbleTimeInterval: Sendable, Equatable {
case seconds(Int)
Expand All @@ -15,19 +7,6 @@ public enum NimbleTimeInterval: Sendable, Equatable {
}

extension NimbleTimeInterval: CustomStringConvertible {
public var dispatchTimeInterval: DispatchTimeInterval {
switch self {
case .seconds(let int):
return .seconds(int)
case .milliseconds(let int):
return .milliseconds(int)
case .microseconds(let int):
return .microseconds(int)
case .nanoseconds(let int):
return .nanoseconds(int)
}
}

// ** Note: We cannot simply divide the time interval because NimbleTimeInterval associated value type is Int
internal var divided: NimbleTimeInterval {
switch self {
Expand All @@ -46,10 +25,31 @@ extension NimbleTimeInterval: CustomStringConvertible {
case let .nanoseconds(val): return "\(Float(val)/1_000_000_000) seconds"
}
}

public static func * (lhs: NimbleTimeInterval, rhs: Int) -> NimbleTimeInterval {
lhs.multiply(by: rhs)
}

public static func * (lhs: Int, rhs: NimbleTimeInterval) -> NimbleTimeInterval {
rhs.multiply(by: lhs)
}

private func multiply(by value: Int) -> NimbleTimeInterval {
switch self {
case let .seconds(int):
return .seconds(int * value)
case let .milliseconds(int):
return .milliseconds(int * value)
case let .microseconds(int):
return .microseconds(int * value)
case let .nanoseconds(int):
return .nanoseconds(int * value)
}
}
}

#if canImport(Foundation)
import typealias Foundation.TimeInterval
import Foundation

extension TimeInterval {
var nimbleInterval: NimbleTimeInterval {
Expand All @@ -58,6 +58,63 @@ extension TimeInterval {
return microseconds < Int.max ? .microseconds(Int(microseconds)) : .seconds(Int(self))
}
}

@available(macOS 13, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
extension NimbleTimeInterval {
public var duration: Duration {
switch self {
case let .seconds(int):
return .seconds(int)
case let .milliseconds(int):
return .milliseconds(int)
case let .microseconds(int):
return .microseconds(int)
case let .nanoseconds(int):
return .nanoseconds(int)
}
}

public init(duration: Duration) {
let (seconds, attoseconds) = duration.components

if attoseconds == 0 {
self = .seconds(Int(seconds))
return
}

let nanoseconds = attoseconds / 1_000_000_000
if (nanoseconds % 1_000_000) == 0 {
self = .milliseconds((Int(seconds) * 1_000) + Int(nanoseconds / 1_000_000))
} else if (nanoseconds % 1_000) == 0 {
self = .microseconds((Int(seconds) * 1_000_000) + Int(nanoseconds / 1_000))
} else {
self = .nanoseconds((Int(seconds) * 1_000_000_000) + Int(nanoseconds))
}
}
}

#endif // canImport(Foundation)

#if !os(WASI)
import Dispatch

#if canImport(CDispatch)
import CDispatch
#endif

extension NimbleTimeInterval {
public var dispatchTimeInterval: DispatchTimeInterval {
switch self {
case let .seconds(int):
return .seconds(int)
case let .milliseconds(int):
return .milliseconds(int)
case let .microseconds(int):
return .microseconds(int)
case let .nanoseconds(int):
return .nanoseconds(int)
}
}
}

#endif // #if !os(WASI)
44 changes: 44 additions & 0 deletions Tests/NimbleTests/NimbleTimeIntervalTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Nimble
import XCTest
import Foundation

final class NimbleTimeIntervalTests: XCTestCase {
func testMultiply() {
expect(NimbleTimeInterval.seconds(1) * 2) == NimbleTimeInterval.seconds(2)
expect(2 * NimbleTimeInterval.seconds(1)) == NimbleTimeInterval.seconds(2)

expect(NimbleTimeInterval.milliseconds(1) * 2) == NimbleTimeInterval.milliseconds(2)
expect(2 * NimbleTimeInterval.milliseconds(1)) == NimbleTimeInterval.milliseconds(2)

expect(NimbleTimeInterval.microseconds(1) * 2) == NimbleTimeInterval.microseconds(2)
expect(2 * NimbleTimeInterval.microseconds(1)) == NimbleTimeInterval.microseconds(2)

expect(NimbleTimeInterval.nanoseconds(1) * 2) == NimbleTimeInterval.nanoseconds(2)
expect(2 * NimbleTimeInterval.nanoseconds(1)) == NimbleTimeInterval.nanoseconds(2)
}

@available(macOS 13, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
func testToDuration() throws {
expect(NimbleTimeInterval.seconds(1).duration).to(equal(Duration.seconds(1)))
expect(NimbleTimeInterval.milliseconds(10).duration).to(equal(Duration.milliseconds(10)))
expect(NimbleTimeInterval.microseconds(20).duration).to(equal(Duration.microseconds(20)))
expect(NimbleTimeInterval.nanoseconds(30).duration).to(equal(Duration.nanoseconds(30)))
}

@available(macOS 13, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
func testFromDuration() throws {
expect(NimbleTimeInterval(duration: Duration.seconds(10))).to(equal(.seconds(10)))

expect(NimbleTimeInterval(duration: Duration.milliseconds(1000))).to(equal(.seconds(1)))
expect(NimbleTimeInterval(duration: Duration.milliseconds(1001))).to(equal(.milliseconds(1001)))

expect(NimbleTimeInterval(duration: Duration.microseconds(1_000_000))).to(equal(.seconds(1)))
expect(NimbleTimeInterval(duration: Duration.microseconds(1_001_000))).to(equal(.milliseconds(1001)))
expect(NimbleTimeInterval(duration: Duration.microseconds(1_001_010))).to(equal(.microseconds(1_001_010)))

expect(NimbleTimeInterval(duration: Duration.nanoseconds(1_000_000_000))).to(equal(.seconds(1)))
expect(NimbleTimeInterval(duration: Duration.nanoseconds(1_001_000_000))).to(equal(.milliseconds(1001)))
expect(NimbleTimeInterval(duration: Duration.nanoseconds(1_001_010_000))).to(equal(.microseconds(1_001_010)))
expect(NimbleTimeInterval(duration: Duration.nanoseconds(1_001_010_100))).to(equal(.nanoseconds(1_001_010_100)))
}
}
Loading