1
- import _CPowSupport
2
-
3
1
#if compiler(<6.2)
4
2
@available ( iOS 18 . 0 , macCatalyst 18 . 0 , macOS 15 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , watchOS 11 . 0 , * )
5
3
extension Duration {
@@ -15,53 +13,47 @@ extension Duration {
15
13
@available ( iOS 16 . 0 , macCatalyst 16 . 0 , macOS 13 . 0 , tvOS 16 . 0 , visionOS 1 . 0 , watchOS 9 . 0 , * )
16
14
public protocol BackoffStrategy < Duration> {
17
15
associatedtype Duration : DurationProtocol
18
- mutating func duration( _ attempt: Int ) -> Duration
19
- mutating func duration( _ attempt: Int , using generator: inout some RandomNumberGenerator ) -> Duration
20
- }
21
-
22
- @available ( iOS 16 . 0 , macCatalyst 16 . 0 , macOS 13 . 0 , tvOS 16 . 0 , visionOS 1 . 0 , watchOS 9 . 0 , * )
23
- extension BackoffStrategy {
24
- @inlinable public mutating func duration( _ attempt: Int , using generator: inout some RandomNumberGenerator ) -> Duration {
25
- return duration ( attempt)
26
- }
16
+ mutating func nextDuration( ) -> Duration
27
17
}
28
18
29
19
@available ( iOS 16 . 0 , macCatalyst 16 . 0 , macOS 13 . 0 , tvOS 16 . 0 , visionOS 1 . 0 , watchOS 9 . 0 , * )
30
20
@usableFromInline
31
21
struct ConstantBackoffStrategy < Duration: DurationProtocol > : BackoffStrategy {
32
- @usableFromInline let c : Duration
33
- @usableFromInline init ( c : Duration ) {
34
- self . c = c
22
+ @usableFromInline let constant : Duration
23
+ @usableFromInline init ( constant : Duration ) {
24
+ self . constant = constant
35
25
}
36
- @inlinable func duration ( _ attempt : Int ) -> Duration {
37
- return c
26
+ @inlinable func nextDuration ( ) -> Duration {
27
+ return constant
38
28
}
39
29
}
40
30
41
31
@available ( iOS 16 . 0 , macCatalyst 16 . 0 , macOS 13 . 0 , tvOS 16 . 0 , visionOS 1 . 0 , watchOS 9 . 0 , * )
42
32
@usableFromInline
43
33
struct LinearBackoffStrategy < Duration: DurationProtocol > : BackoffStrategy {
44
- @usableFromInline let a : Duration
45
- @usableFromInline let b : Duration
46
- @usableFromInline init ( a : Duration , b : Duration ) {
47
- self . a = a
48
- self . b = b
34
+ @usableFromInline var current : Duration
35
+ @usableFromInline var increment : Duration
36
+ @usableFromInline init ( increment : Duration , initial : Duration ) {
37
+ self . current = initial
38
+ self . increment = increment
49
39
}
50
- @inlinable func duration( _ attempt: Int ) -> Duration {
51
- return a * attempt + b
40
+ @inlinable mutating func nextDuration( ) -> Duration {
41
+ defer { current += increment }
42
+ return current
52
43
}
53
44
}
54
45
55
46
@available ( iOS 16 . 0 , macCatalyst 16 . 0 , macOS 13 . 0 , tvOS 16 . 0 , visionOS 1 . 0 , watchOS 9 . 0 , * )
56
- @usableFromInline struct ExponentialBackoffStrategy : BackoffStrategy {
57
- @usableFromInline let a : Duration
58
- @usableFromInline let b : Double
59
- @usableFromInline init ( a : Duration , b : Double ) {
60
- self . a = a
61
- self . b = b
47
+ @usableFromInline struct ExponentialBackoffStrategy < Duration : DurationProtocol > : BackoffStrategy {
48
+ @usableFromInline var current : Duration
49
+ @usableFromInline let factor : Int
50
+ @usableFromInline init ( factor : Int , initial : Duration ) {
51
+ self . current = initial
52
+ self . factor = factor
62
53
}
63
- @inlinable func duration( _ attempt: Int ) -> Duration {
64
- return a * pow( b, Double ( attempt) )
54
+ @inlinable mutating func nextDuration( ) -> Duration {
55
+ defer { current *= factor }
56
+ return current
65
57
}
66
58
}
67
59
@@ -74,11 +66,8 @@ struct MinimumBackoffStrategy<Base: BackoffStrategy>: BackoffStrategy {
74
66
self . base = base
75
67
self . minimum = minimum
76
68
}
77
- @inlinable mutating func duration( _ attempt: Int ) -> Base . Duration {
78
- return max ( minimum, base. duration ( attempt) )
79
- }
80
- @inlinable mutating func duration( _ attempt: Int , using generator: inout some RandomNumberGenerator ) -> Base . Duration {
81
- return max ( minimum, base. duration ( attempt, using: & generator) )
69
+ @inlinable mutating func nextDuration( ) -> Base . Duration {
70
+ return max ( minimum, base. nextDuration ( ) )
82
71
}
83
72
}
84
73
@@ -91,86 +80,80 @@ struct MaximumBackoffStrategy<Base: BackoffStrategy>: BackoffStrategy {
91
80
self . base = base
92
81
self . maximum = maximum
93
82
}
94
- @inlinable mutating func duration( _ attempt: Int ) -> Base . Duration {
95
- return min ( maximum, base. duration ( attempt) )
96
- }
97
- @inlinable mutating func duration( _ attempt: Int , using generator: inout some RandomNumberGenerator ) -> Base . Duration {
98
- return min ( maximum, base. duration ( attempt, using: & generator) )
83
+ @inlinable mutating func nextDuration( ) -> Base . Duration {
84
+ return min ( maximum, base. nextDuration ( ) )
99
85
}
100
86
}
101
87
102
88
@available ( iOS 18 . 0 , macCatalyst 18 . 0 , macOS 15 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , watchOS 11 . 0 , * )
103
89
@usableFromInline
104
- struct FullJitterBackoffStrategy < Base: BackoffStrategy > : BackoffStrategy where Base. Duration == Swift . Duration {
90
+ struct FullJitterBackoffStrategy < Base: BackoffStrategy , RNG : RandomNumberGenerator > : BackoffStrategy where Base. Duration == Swift . Duration {
105
91
@usableFromInline var base : Base
106
- @usableFromInline init ( base: Base ) {
92
+ @usableFromInline var generator : RNG
93
+ @usableFromInline init ( base: Base , generator: RNG ) {
107
94
self . base = base
95
+ self . generator = generator
108
96
}
109
- @inlinable mutating func duration( _ attempt: Int ) -> Base . Duration {
110
- return . init( attoseconds: Int128 . random ( in: 0 ... base. duration ( attempt) . attoseconds) )
111
- }
112
- @inlinable mutating func duration( _ attempt: Int , using generator: inout some RandomNumberGenerator ) -> Base . Duration {
113
- return . init( attoseconds: Int128 . random ( in: 0 ... base. duration ( attempt, using: & generator) . attoseconds, using: & generator) )
97
+ @inlinable mutating func nextDuration( ) -> Base . Duration {
98
+ return . init( attoseconds: Int128 . random ( in: 0 ... base. nextDuration ( ) . attoseconds) )
114
99
}
115
100
}
116
101
117
102
@available ( iOS 18 . 0 , macCatalyst 18 . 0 , macOS 15 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , watchOS 11 . 0 , * )
118
103
@usableFromInline
119
- struct EqualJitterBackoffStrategy < Base: BackoffStrategy > : BackoffStrategy where Base. Duration == Swift . Duration {
104
+ struct EqualJitterBackoffStrategy < Base: BackoffStrategy , RNG : RandomNumberGenerator > : BackoffStrategy where Base. Duration == Swift . Duration {
120
105
@usableFromInline var base : Base
121
- @usableFromInline init ( base: Base ) {
106
+ @usableFromInline var generator : RNG
107
+ @usableFromInline init ( base: Base , generator: RNG ) {
122
108
self . base = base
109
+ self . generator = generator
123
110
}
124
- @inlinable mutating func duration( _ attempt: Int ) -> Base . Duration {
125
- let halfBase = ( base. duration ( attempt) / 2 ) . attoseconds
126
- return . init( attoseconds: halfBase + Int128. random ( in: 0 ... halfBase) )
127
- }
128
- @inlinable mutating func duration( _ attempt: Int , using generator: inout some RandomNumberGenerator ) -> Base . Duration {
129
- let halfBase = ( base. duration ( attempt, using: & generator) / 2 ) . attoseconds
111
+ @inlinable mutating func nextDuration( ) -> Base . Duration {
112
+ let halfBase = ( base. nextDuration ( ) / 2 ) . attoseconds
130
113
return . init( attoseconds: halfBase + Int128. random ( in: 0 ... halfBase, using: & generator) )
131
114
}
132
115
}
133
116
134
117
@available ( iOS 18 . 0 , macCatalyst 18 . 0 , macOS 15 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , watchOS 11 . 0 , * )
135
118
@usableFromInline
136
- struct DecorrelatedJitterBackoffStrategy < Base: BackoffStrategy > : BackoffStrategy where Base. Duration == Swift . Duration {
119
+ struct DecorrelatedJitterBackoffStrategy < Base: BackoffStrategy , RNG : RandomNumberGenerator > : BackoffStrategy where Base. Duration == Swift . Duration {
137
120
@usableFromInline var base : Base
138
- @usableFromInline let divisor : Int128
139
- @usableFromInline var previousDuration : Duration ?
140
- @usableFromInline init ( base: Base , divisor: Int128 ) {
121
+ @usableFromInline var generator : RNG
122
+ @usableFromInline var current : Duration ?
123
+ @usableFromInline let factor : Int
124
+ @usableFromInline init ( base: Base , generator: RNG , factor: Int ) {
141
125
self . base = base
142
- self . divisor = divisor
143
- }
144
- @inlinable mutating func duration( _ attempt: Int ) -> Base . Duration {
145
- let base = base. duration ( attempt)
146
- let previousDuration = previousDuration ?? base
147
- self . previousDuration = previousDuration
148
- return . init( attoseconds: Int128 . random ( in: base. attoseconds... previousDuration. attoseconds / divisor) )
126
+ self . generator = generator
127
+ self . factor = factor
149
128
}
150
- @inlinable mutating func duration( _ attempt: Int , using generator: inout some RandomNumberGenerator ) -> Base . Duration {
151
- let base = base. duration ( attempt, using: & generator)
152
- let previousDuration = previousDuration ?? base
153
- self . previousDuration = previousDuration
154
- return . init( attoseconds: Int128 . random ( in: base. attoseconds... previousDuration. attoseconds / divisor, using: & generator) )
129
+ @inlinable mutating func nextDuration( ) -> Base . Duration {
130
+ let base = base. nextDuration ( )
131
+ let current = current ?? base
132
+ let next = Duration ( attoseconds: Int128 . random ( in: base. attoseconds... ( current * factor) . attoseconds, using: & generator) )
133
+ self . current = next
134
+ return next
155
135
}
156
136
}
157
137
158
138
@available ( iOS 16 . 0 , macCatalyst 16 . 0 , macOS 13 . 0 , tvOS 16 . 0 , visionOS 1 . 0 , watchOS 9 . 0 , * )
159
139
public enum Backoff {
160
- @inlinable public static func constant< Duration: DurationProtocol > ( _ c: Duration ) -> some BackoffStrategy < Duration > {
161
- return ConstantBackoffStrategy ( c: c)
140
+ @inlinable public static func constant< Duration: DurationProtocol > ( _ constant: Duration ) -> some BackoffStrategy < Duration > {
141
+ return ConstantBackoffStrategy ( constant: constant)
142
+ }
143
+ @inlinable public static func constant( _ constant: Duration ) -> some BackoffStrategy < Duration > {
144
+ return ConstantBackoffStrategy ( constant: constant)
162
145
}
163
- @inlinable public static func constant ( _ c : Duration ) -> some BackoffStrategy < Duration > {
164
- return ConstantBackoffStrategy ( c : c )
146
+ @inlinable public static func linear < Duration : DurationProtocol > ( increment : Duration , initial : Duration ) -> some BackoffStrategy < Duration > {
147
+ return LinearBackoffStrategy ( increment : increment , initial : initial )
165
148
}
166
- @inlinable public static func linear< Duration : DurationProtocol > ( increment a : Duration , initial b : Duration ) -> some BackoffStrategy < Duration > {
167
- return LinearBackoffStrategy ( a : a , b : b )
149
+ @inlinable public static func linear( increment: Duration , initial: Duration ) -> some BackoffStrategy < Duration > {
150
+ return LinearBackoffStrategy ( increment : increment , initial : initial )
168
151
}
169
- @inlinable public static func linear ( increment a : Duration , initial b : Duration ) -> some BackoffStrategy < Duration > {
170
- return LinearBackoffStrategy ( a : a , b : b )
152
+ @inlinable public static func exponential < Duration : DurationProtocol > ( factor : Int , initial: Duration ) -> some BackoffStrategy < Duration > {
153
+ return ExponentialBackoffStrategy ( factor : factor , initial : initial )
171
154
}
172
- @inlinable public static func exponential( multiplier b : Double = 2 , initial a : Duration ) -> some BackoffStrategy < Duration > {
173
- return ExponentialBackoffStrategy ( a : a , b : b )
155
+ @inlinable public static func exponential( factor : Int , initial: Duration ) -> some BackoffStrategy < Duration > {
156
+ return ExponentialBackoffStrategy ( factor : factor , initial : initial )
174
157
}
175
158
}
176
159
@@ -186,13 +169,13 @@ extension BackoffStrategy {
186
169
187
170
@available ( iOS 18 . 0 , macCatalyst 18 . 0 , macOS 15 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , watchOS 11 . 0 , * )
188
171
extension BackoffStrategy where Duration == Swift . Duration {
189
- @inlinable public func fullJitter( ) -> some BackoffStrategy < Duration > {
190
- return FullJitterBackoffStrategy ( base: self )
172
+ @inlinable public func fullJitter< RNG : RandomNumberGenerator > ( using generator : RNG = SystemRandomNumberGenerator ( ) ) -> some BackoffStrategy < Duration > {
173
+ return FullJitterBackoffStrategy ( base: self , generator : generator )
191
174
}
192
- @inlinable public func equalJitter( ) -> some BackoffStrategy < Duration > {
193
- return EqualJitterBackoffStrategy ( base: self )
175
+ @inlinable public func equalJitter< RNG : RandomNumberGenerator > ( using generator : RNG = SystemRandomNumberGenerator ( ) ) -> some BackoffStrategy < Duration > {
176
+ return EqualJitterBackoffStrategy ( base: self , generator : generator )
194
177
}
195
- @inlinable public func decorrelatedJitter( divisor : Int = 3 ) -> some BackoffStrategy < Duration > {
196
- return DecorrelatedJitterBackoffStrategy ( base: self , divisor : Int128 ( divisor ) )
178
+ @inlinable public func decorrelatedJitter< RNG : RandomNumberGenerator > ( factor : Int , using generator : RNG = SystemRandomNumberGenerator ( ) ) -> some BackoffStrategy < Duration > {
179
+ return DecorrelatedJitterBackoffStrategy ( base: self , generator : generator , factor : factor )
197
180
}
198
181
}
0 commit comments