99// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010//
1111//===----------------------------------------------------------------------===//
12- // Keep all interop logiv here
12+
1313#if FOUNDATION_FRAMEWORK
1414internal import _ForSwiftFoundation
15+ internal import Synchronization
16+
1517@available ( FoundationPreview 6 . 2 , * )
16- //MARK: Progress Parent - ProgressManager Child Interop
17- // Actual Progress Parent
18- // Ghost Progress Parent
19- // Ghost ProgressManager Child
20- // Actual ProgressManager Child
18+ //MARK: Progress Parent - Subprogress / ProgressReporter Child Interop
2119extension Progress {
2220
2321 /// Returns a Subprogress which can be passed to any method that reports progress
@@ -30,28 +28,27 @@ extension Progress {
3028 /// - Returns: A `Subprogress` instance.
3129 public func makeChild( withPendingUnitCount count: Int ) -> Subprogress {
3230
33- // Make ghost parent & add it to actual parent's children list
34- let topProgress = Progress ( totalUnitCount: 1 )
35- self . addChild ( topProgress, withPendingUnitCount: Int64 ( count) )
31+ // Make a ProgressManager
32+ let manager = ProgressManager ( totalCount: 1 )
3633
37- // Make ghost child
38- let bottomProgress = ProgressManager ( totalCount: 1 )
34+ // Create a NSProgress - ProgressManager bridge for mirroring
35+ let subprogressBridge = SubprogressBridge (
36+ parent: self ,
37+ portion: Int64 ( count) ,
38+ manager: manager
39+ )
3940
40- // Make observation instance
41- let managerObservation = _NSProgressParentSubprogressChild (
42- ghostParent: topProgress,
43- ghostChild: bottomProgress
41+ // Instantiate a Subprogress with ProgressManager as parent
42+ // Store bridge
43+ let subprogress = Subprogress (
44+ parent: manager,
45+ portionOfParent: 1 ,
46+ subprogressBridge: subprogressBridge
4447 )
4548
46- // Make actual child with ghost child being parent
47- var subprogress = Subprogress ( parent: bottomProgress, portionOfParent: 1 )
48- bottomProgress. subprogress ( assigningCount: 1 )
49- subprogress. managerObservation = managerObservation
50- subprogress. progressParentProgressManagerChildMessenger = bottomProgress
5149 return subprogress
5250 }
5351
54-
5552 /// Adds a ProgressReporter as a child to a Progress, which constitutes a portion of Progress's totalUnitCount.
5653 ///
5754 /// - Parameters:
@@ -61,17 +58,15 @@ extension Progress {
6158
6259 precondition ( self . isCycle ( reporter: reporter) == false , " Creating a cycle is not allowed. " )
6360
64- // Make intermediary & add it to NSProgress parent's children list
65- let ghostProgressParent = Progress ( totalUnitCount: Int64 ( reporter. manager. totalCount ?? 0 ) )
66- ghostProgressParent. completedUnitCount = Int64 ( reporter. manager. completedCount)
67- self . addChild ( ghostProgressParent, withPendingUnitCount: Int64 ( count) )
68-
69- // Make observation instance
70- let reporterObservation = _NSProgressParentProgressReporterChild (
71- intermediary: ghostProgressParent,
72- reporter: reporter
61+ // Create a NSProgress - ProgressReporter bridge
62+ let reporterBridge = ProgressReporterBridge (
63+ parent: self ,
64+ portion: Int64 ( count) ,
65+ reporterBridge: reporter
7366 )
74- reporter. manager. setInteropObservationReporter ( observation: reporterObservation)
67+
68+ // Store bridge
69+ reporter. manager. addBridge ( reporterBridge: reporterBridge)
7570 }
7671
7772 // MARK: Cycle detection
@@ -80,11 +75,11 @@ extension Progress {
8075 return false
8176 }
8277
83- if !( self . _parent ( ) is _NSProgressParentBridge ) {
78+ if !( self . _parent ( ) is NSProgressBridge ) {
8479 return self . _parent ( ) . isCycle ( reporter: reporter)
8580 }
8681
87- let unwrappedParent = ( self . _parent ( ) as? _NSProgressParentBridge ) ? . actualParent
82+ let unwrappedParent = ( self . _parent ( ) as? NSProgressBridge ) ? . manager
8883 if let unwrappedParent = unwrappedParent {
8984 if unwrappedParent === reporter. manager {
9085 return true
@@ -96,105 +91,178 @@ extension Progress {
9691 }
9792}
9893
99- internal final class _NSProgressParentSubprogressChild : Sendable {
100- private let ghostParent : Progress
101- private let ghostChild : ProgressManager
102-
103- fileprivate init ( ghostParent: Progress , ghostChild: ProgressManager ) {
104- self . ghostParent = ghostParent
105- self . ghostChild = ghostChild
94+ @available ( FoundationPreview 6 . 2 , * )
95+ //MARK: ProgressManager Parent - Progress Child Interop
96+ extension ProgressManager {
97+
98+ /// Adds a Foundation's `Progress` instance as a child which constitutes a certain `count` of `self`'s `totalCount`.
99+ /// - Parameters:
100+ /// - count: Number of units delegated from `self`'s `totalCount`.
101+ /// - progress: `Progress` which receives the delegated `count`.
102+ public func subprogress( assigningCount count: Int , to progress: Foundation . Progress ) {
103+ precondition ( progress. _parent ( ) == nil , " Cannot assign a progress to more than one parent. " )
104+
105+ // Create a ProgressManager - NSProgress bridge
106+ let progressBridge = NSProgressBridge (
107+ manager: self ,
108+ progress: progress,
109+ portion: count
110+ )
106111
107- // Set up mirroring observation relationship between ghostChild and ghostParent
108- // - Ghost Parent should mirror values from Ghost Child, and Ghost Child just mirrors values of Actual Child
109- ghostChild. addObserver { [ weak self] observerState in
112+ // Add bridge as a parent
113+ progress. _setParent ( progressBridge, portion: Int64 ( count) )
114+
115+ // Store bridge
116+ self . addBridge ( nsProgressBridge: progressBridge)
117+ }
118+ }
119+
120+ internal final class SubprogressBridge : Sendable {
121+
122+ internal let progressBridge : Progress
123+ internal let manager : ProgressManager
124+
125+ init ( parent: Progress , portion: Int64 , manager: ProgressManager ) {
126+ self . manager = manager
127+ self . progressBridge = Progress ( totalUnitCount: 1 , parent: parent, pendingUnitCount: portion)
128+
129+ manager. addObserver { [ weak self] observerState in
110130 guard let self else {
111131 return
112132 }
113133
114134 switch observerState {
115135 case . fractionUpdated( let totalCount, let completedCount) :
116- self . ghostParent . completedUnitCount = Int64 ( completedCount)
117- self . ghostParent . totalUnitCount = Int64 ( totalCount)
136+ self . progressBridge . completedUnitCount = Int64 ( completedCount)
137+ self . progressBridge . totalUnitCount = Int64 ( totalCount)
118138 }
119139 }
120140 }
121141}
122142
123- internal final class _NSProgressParentProgressReporterChild : Sendable {
124- private let intermediary : Progress
125- private let reporter : ProgressReporter
143+ internal final class ProgressReporterBridge : Sendable {
144+
145+ internal let progressBridge : Progress
146+ internal let reporterBridge : ProgressReporter
126147
127- fileprivate init ( intermediary: Progress , reporter: ProgressReporter ) {
128- self . intermediary = intermediary
129- self . reporter = reporter
148+ init ( parent: Progress , portion: Int64 , reporterBridge: ProgressReporter ) {
149+ self . progressBridge = Progress (
150+ totalUnitCount: Int64 ( reporterBridge. manager. totalCount ?? 0 ) ,
151+ parent: parent,
152+ pendingUnitCount: portion
153+ )
154+ self . progressBridge. completedUnitCount = Int64 ( reporterBridge. manager. completedCount)
155+ self . reporterBridge = reporterBridge
156+
157+ let manager = reporterBridge. manager
130158
131- reporter . manager. addObserver { [ weak self] observerState in
159+ manager. addObserver { [ weak self] observerState in
132160 guard let self else {
133161 return
134162 }
135163
136164 switch observerState {
137165 case . fractionUpdated( let totalCount, let completedCount) :
138- self . intermediary . completedUnitCount = Int64 ( completedCount)
139- self . intermediary . totalUnitCount = Int64 ( totalCount)
166+ self . progressBridge . completedUnitCount = Int64 ( completedCount)
167+ self . progressBridge . totalUnitCount = Int64 ( totalCount)
140168 }
141169 }
142170 }
143171
144172}
145173
146- @available ( FoundationPreview 6 . 2 , * )
147- //MARK: ProgressManager Parent - Progress Child Interop
148- extension ProgressManager {
149-
150- /// Adds a Foundation's `Progress` instance as a child which constitutes a certain `count` of `self`'s `totalCount`.
151- /// - Parameters:
152- /// - count: Number of units delegated from `self`'s `totalCount`.
153- /// - progress: `Progress` which receives the delegated `count`.
154- public func subprogress( assigningCount count: Int , to progress: Foundation . Progress ) {
155- precondition ( progress. _parent ( ) == nil , " Cannot assign a progress to more than one parent. " )
156-
157- let parentBridge = _NSProgressParentBridge ( managerParent: self , progressChild: progress, portion: count)
158- progress. _setParent ( parentBridge, portion: Int64 ( count) )
159-
160- // Save ghost parent in ProgressManager so it doesn't go out of scope after assign method ends
161- // So that when NSProgress increases completedUnitCount and queries for parent there is still a reference to ghostParent and parent doesn't show 0x0 (portion: 5)
162- self . setParentBridge ( parentBridge: parentBridge)
163- }
164- }
165-
166- // Subclass of Foundation.Progress
167- internal final class _NSProgressParentBridge : Progress , @unchecked Sendable {
174+ internal final class NSProgressBridge : Progress , @unchecked Sendable {
168175
169- internal let actualParent : ProgressManager
170- internal let actualChild : Progress
171- internal let ghostChild : ProgressManager
176+ internal let manager : ProgressManager
177+ internal let managerBridge : ProgressManager
178+ internal let progress : Progress
172179
173- init ( managerParent : ProgressManager , progressChild : Progress , portion: Int ) {
174- self . actualParent = managerParent
175- self . actualChild = progressChild
176- self . ghostChild = ProgressManager ( totalCount : Int ( progressChild . totalUnitCount ) )
180+ init ( manager : ProgressManager , progress : Progress , portion: Int ) {
181+ self . manager = manager
182+ self . managerBridge = ProgressManager ( totalCount : Int ( progress . totalUnitCount ) )
183+ self . progress = progress
177184 super. init ( parent: nil , userInfo: nil )
178185
179- // Make ghostChild mirror progressChild, ghostChild is added as a child to managerParent
180- ghostChild. withProperties { properties in
181- properties. completedCount = Int ( progressChild. completedUnitCount)
186+ managerBridge. withProperties { properties in
187+ properties. completedCount = Int ( progress. completedUnitCount)
182188 }
183189
184- let position = managerParent. addChild ( child: ghostChild, portion: portion, childFraction: ProgressFraction ( completed: Int ( completedUnitCount) , total: Int ( totalUnitCount) ) )
185-
186- ghostChild. addParent ( parent: managerParent, positionInParent: position)
190+ let position = manager. addChild (
191+ child: managerBridge,
192+ portion: portion,
193+ childFraction: ProgressFraction ( completed: Int ( completedUnitCount) , total: Int ( totalUnitCount) )
194+ )
195+ managerBridge. addParent ( parent: manager, positionInParent: position)
187196 }
188197
189198 // Overrides the _updateChild func that Foundation.Progress calls to update parent
190199 // so that the parent that gets updated is the ProgressManager parent
191200 override func _updateChild( _ child: Foundation . Progress , fraction: _NSProgressFractionTuple , portion: Int64 ) {
192- ghostChild . withProperties { properties in
201+ managerBridge . withProperties { properties in
193202 properties. totalCount = Int ( fraction. next. total)
194203 properties. completedCount = Int ( fraction. next. completed)
195204 }
196205
197- ghostChild. markSelfDirty ( )
206+ managerBridge. markSelfDirty ( )
207+ }
208+ }
209+
210+ @available ( FoundationPreview 6 . 2 , * )
211+ extension ProgressManager {
212+ internal enum ObserverState {
213+ case fractionUpdated( totalCount: Int , completedCount: Int )
214+ }
215+
216+ internal struct InteropObservation {
217+ let subprogressBridge : SubprogressBridge ?
218+ var reporterBridge : ProgressReporterBridge ?
219+ var nsProgressBridge : Foundation . Progress ?
220+ }
221+ }
222+
223+ extension ProgressManager . State {
224+ internal func notifyObservers( with observerState: ProgressManager . ObserverState ) {
225+ for observer in observers {
226+ observer ( observerState)
227+ }
228+ }
229+ }
230+
231+ @available ( FoundationPreview 6 . 2 , * )
232+ extension ProgressManager {
233+ //MARK: Interop Methods
234+ /// Adds `observer` to list of `_observers` in `self`.
235+ internal func addObserver( observer: @escaping @Sendable ( ObserverState ) -> Void ) {
236+ state. withLock { state in
237+ state. observers. append ( observer)
238+ }
239+ }
240+
241+ /// Notifies all `_observers` of `self` when `state` changes.
242+ internal func notifyObservers( with observedState: ObserverState ) {
243+ state. withLock { state in
244+ for observer in state. observers {
245+ observer ( observedState)
246+ }
247+ }
248+ }
249+
250+ internal func addBridge( reporterBridge: ProgressReporterBridge ? = nil , nsProgressBridge: Foundation . Progress ? = nil ) {
251+ state. withLock { state in
252+ if let reporterBridge {
253+ state. interopObservation. reporterBridge = reporterBridge
254+ }
255+
256+ if let nsProgressBridge {
257+ state. interopObservation. nsProgressBridge = nsProgressBridge
258+ }
259+ }
260+ }
261+
262+ internal func setInteropChild( interopChild: ProgressManager ) {
263+ state. withLock { state in
264+ state. interopChild = interopChild
265+ }
198266 }
199267}
200268#endif
0 commit comments