1- import _CPowSupport
2-
31#if compiler(<6.2)
42@available ( iOS 18 . 0 , macCatalyst 18 . 0 , macOS 15 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , watchOS 11 . 0 , * )
53extension Duration {
@@ -15,53 +13,47 @@ extension Duration {
1513@available ( iOS 16 . 0 , macCatalyst 16 . 0 , macOS 13 . 0 , tvOS 16 . 0 , visionOS 1 . 0 , watchOS 9 . 0 , * )
1614public protocol BackoffStrategy < Duration> {
1715 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
2717}
2818
2919@available ( iOS 16 . 0 , macCatalyst 16 . 0 , macOS 13 . 0 , tvOS 16 . 0 , visionOS 1 . 0 , watchOS 9 . 0 , * )
3020@usableFromInline
3121struct 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
3525 }
36- @inlinable func duration ( _ attempt : Int ) -> Duration {
37- return c
26+ @inlinable func nextDuration ( ) -> Duration {
27+ return constant
3828 }
3929}
4030
4131@available ( iOS 16 . 0 , macCatalyst 16 . 0 , macOS 13 . 0 , tvOS 16 . 0 , visionOS 1 . 0 , watchOS 9 . 0 , * )
4232@usableFromInline
4333struct 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
4939 }
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
5243 }
5344}
5445
5546@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
6253 }
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
6557 }
6658}
6759
@@ -74,11 +66,8 @@ struct MinimumBackoffStrategy<Base: BackoffStrategy>: BackoffStrategy {
7466 self . base = base
7567 self . minimum = minimum
7668 }
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 ( ) )
8271 }
8372}
8473
@@ -91,86 +80,80 @@ struct MaximumBackoffStrategy<Base: BackoffStrategy>: BackoffStrategy {
9180 self . base = base
9281 self . maximum = maximum
9382 }
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 ( ) )
9985 }
10086}
10187
10288@available ( iOS 18 . 0 , macCatalyst 18 . 0 , macOS 15 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , watchOS 11 . 0 , * )
10389@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 {
10591 @usableFromInline var base : Base
106- @usableFromInline init ( base: Base ) {
92+ @usableFromInline var generator : RNG
93+ @usableFromInline init ( base: Base , generator: RNG ) {
10794 self . base = base
95+ self . generator = generator
10896 }
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) )
11499 }
115100}
116101
117102@available ( iOS 18 . 0 , macCatalyst 18 . 0 , macOS 15 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , watchOS 11 . 0 , * )
118103@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 {
120105 @usableFromInline var base : Base
121- @usableFromInline init ( base: Base ) {
106+ @usableFromInline var generator : RNG
107+ @usableFromInline init ( base: Base , generator: RNG ) {
122108 self . base = base
109+ self . generator = generator
123110 }
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
130113 return . init( attoseconds: halfBase + Int128. random ( in: 0 ... halfBase, using: & generator) )
131114 }
132115}
133116
134117@available ( iOS 18 . 0 , macCatalyst 18 . 0 , macOS 15 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , watchOS 11 . 0 , * )
135118@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 {
137120 @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 ) {
141125 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
149128 }
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
155135 }
156136}
157137
158138@available ( iOS 16 . 0 , macCatalyst 16 . 0 , macOS 13 . 0 , tvOS 16 . 0 , visionOS 1 . 0 , watchOS 9 . 0 , * )
159139public 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)
162145 }
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 )
165148 }
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 )
168151 }
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 )
171154 }
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 )
174157 }
175158}
176159
@@ -186,13 +169,13 @@ extension BackoffStrategy {
186169
187170@available ( iOS 18 . 0 , macCatalyst 18 . 0 , macOS 15 . 0 , tvOS 18 . 0 , visionOS 2 . 0 , watchOS 11 . 0 , * )
188171extension 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 )
191174 }
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 )
194177 }
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 )
197180 }
198181}
0 commit comments