44//
55// Audited for iOS 18.0
66// Status: WIP
7+ // ID: 5A14269649C60F846422EA0FA4C5E535 (SwiftUI)
8+ // ID: 43DA1754B0518AF1D72B90677BF266DB (SwiftUICore)
79
810public import Foundation
911import OpenGraphShims
1012import OpenSwiftUI_SPI
1113
14+ /// Namespace for view debug information.
1215public enum _ViewDebug {
16+ /// All debuggable view properties.
1317 public enum Property : UInt32 , Hashable {
1418 case type
1519 case value
@@ -21,7 +25,8 @@ public enum _ViewDebug {
2125 case layoutComputer
2226 case displayList
2327 }
24-
28+
29+ /// Bitmask of requested view debug properties.
2530 public struct Properties : OptionSet {
2631 public let rawValue : UInt32
2732 public init ( rawValue: UInt32 ) {
@@ -32,7 +37,7 @@ public enum _ViewDebug {
3237 package init ( _ property: Property ) {
3338 self . init ( rawValue: 1 << property. rawValue)
3439 }
35-
40+
3641 public static let type = Properties ( . type)
3742 public static let value = Properties ( . value)
3843 public static let transform = Properties ( . transform)
@@ -47,6 +52,7 @@ public enum _ViewDebug {
4752
4853 package static var properties = Properties ( )
4954
55+ /// View debug data for a view and all its child views.
5056 public struct Data {
5157 package var data : [ Property : Any ]
5258 package var childData : [ _ViewDebug . Data ]
@@ -72,80 +78,120 @@ extension _ViewDebug.Data: Sendable {}
7278@available ( * , unavailable)
7379extension _ViewDebug : Sendable { }
7480
75- // TODO
76- // MARK: View and ViewModifier
77-
78- extension View {
79- @ inline ( __always )
80- nonisolated
81- package static func makeDebuggableView (
82- view : _GraphValue < Self > ,
83- inputs : _ViewInputs
84- ) -> _ViewOutputs {
85- preconditionFailure ( " TODO " )
81+ extension _ViewDebug {
82+ package static func initialize ( inputs : inout _ViewInputs ) {
83+ if !isInitialized {
84+ if let debugValue = EnvironmentHelper . int32 ( for : " OPENSWIFTUI_VIEW_DEBUG " ) {
85+ properties = Properties ( rawValue : UInt32 ( bitPattern : debugValue ) )
86+ }
87+ isInitialized = true
88+ }
89+ if !properties . isEmpty {
90+ Subgraph . setShouldRecordTree ( )
91+ }
8692 }
8793
88- @inline ( __always)
89- nonisolated
90- package static func makeDebuggableViewList(
91- view: _GraphValue < Self > ,
92- inputs: _ViewListInputs
93- ) -> _ViewListOutputs {
94- OGSubgraph . beginTreeElement ( value: view. value, flags: 1 )
95- defer { OGSubgraph . endTreeElement ( value: view. value) }
96- return _makeViewList ( view: view, inputs: inputs)
94+ fileprivate static func reallyWrap< Value> ( _ outputs: inout _ViewOutputs , value: _GraphValue < Value > , inputs: UnsafePointer < _ViewInputs > ) {
95+ var debugProperiets = outputs. preferences. debugProperties. union ( inputs. pointee. changedDebugProperties)
96+ outputs. preferences. debugProperties = [ ]
97+ if debugProperiets. contains ( . layoutComputer) {
98+ debugProperiets. setValue ( outputs. layoutComputer != nil , for: . layoutComputer)
99+ }
100+ guard debugProperiets. subtracting ( . displayList) != [ ] else {
101+ return
102+ }
103+ guard Subgraph . shouldRecordTree else {
104+ return
105+ }
106+ if debugProperiets. contains ( . transform) {
107+ Subgraph . addTreeValue ( inputs. pointee. transform, forKey: " transfrom " , flags: 0 )
108+ }
109+ if debugProperiets. contains ( . position) {
110+ Subgraph . addTreeValue ( inputs. pointee. position, forKey: " position " , flags: 0 )
111+ }
112+ if debugProperiets. contains ( . size) {
113+ Subgraph . addTreeValue ( inputs. pointee. size, forKey: " size " , flags: 0 )
114+ }
115+ if debugProperiets. contains ( . environment) {
116+ Subgraph . addTreeValue ( inputs. pointee. environment, forKey: " environment " , flags: 0 )
117+ }
118+ if debugProperiets. contains ( . phase) {
119+ Subgraph . addTreeValue ( inputs. pointee. base. phase, forKey: " phase " , flags: 0 )
120+ }
121+ if debugProperiets. contains ( . layoutComputer) {
122+ Subgraph . addTreeValue ( outputs. layoutComputer!, forKey: " layoutComputer " , flags: 0 )
123+ }
97124 }
98125}
99126
100- extension ViewModifier {
101- package static func makeDebuggableView(
127+ // MARK: View and ViewModifier
128+
129+ extension ViewModifier {
130+ @inline ( __always)
131+ nonisolated package static func makeDebuggableView(
102132 modifier: _GraphValue < Self > ,
103133 inputs: _ViewInputs ,
104134 body: @escaping ( _Graph , _ViewInputs ) -> _ViewOutputs
105135 ) -> _ViewOutputs {
106- preconditionFailure ( " TODO " )
136+ Subgraph . beginTreeElement ( value: modifier. value, flags: 0 )
137+ var outputs = _makeView (
138+ modifier: modifier,
139+ inputs: inputs. withoutChangedDebugProperties,
140+ body: body
141+ )
142+ if Subgraph . shouldRecordTree {
143+ withUnsafePointer ( to: inputs) { pointer in
144+ _ViewDebug. reallyWrap ( & outputs, value: modifier, inputs: pointer)
145+ }
146+ }
147+ Subgraph . endTreeElement ( value: modifier. value)
148+ return outputs
107149 }
108150
109- static func makeDebuggableViewList(
151+ @inline ( __always)
152+ nonisolated package static func makeDebuggableViewList(
110153 modifier: _GraphValue < Self > ,
111154 inputs: _ViewListInputs ,
112155 body: @escaping ( _Graph , _ViewListInputs ) -> _ViewListOutputs
113156 ) -> _ViewListOutputs {
114- OGSubgraph . beginTreeElement ( value: modifier. value, flags: 1 )
115- defer { OGSubgraph . endTreeElement ( value: modifier. value) }
157+ Subgraph . beginTreeElement ( value: modifier. value, flags: 1 )
158+ defer { Subgraph . endTreeElement ( value: modifier. value) }
116159 return _makeViewList ( modifier: modifier, inputs: inputs, body: body)
117160 }
118161}
119162
120- // MARK: _ViewDebug
121-
122- extension _ViewDebug {
123- public static func serializedData( _ viewDebugData: [ _ViewDebug . Data ] ) -> Foundation . Data ? {
124- let encoder = JSONEncoder ( )
125- encoder. nonConformingFloatEncodingStrategy = . convertToString( positiveInfinity: " inf " , negativeInfinity: " -inf " , nan: " nan " )
126- do {
127- let data = try encoder. encode ( viewDebugData)
128- return data
129- } catch {
130- let dic = [ " error " : error. localizedDescription]
131- return try ? encoder. encode ( dic)
163+ extension View {
164+ @inline ( __always)
165+ nonisolated package static func makeDebuggableView(
166+ view: _GraphValue < Self > ,
167+ inputs: _ViewInputs
168+ ) -> _ViewOutputs {
169+ Subgraph . beginTreeElement ( value: view. value, flags: 0 )
170+ var outputs = _makeView (
171+ view: view,
172+ inputs: inputs. withoutChangedDebugProperties
173+ )
174+ if Subgraph . shouldRecordTree {
175+ withUnsafePointer ( to: inputs) { pointer in
176+ _ViewDebug. reallyWrap ( & outputs, value: view, inputs: pointer)
177+ }
132178 }
179+ Subgraph . endTreeElement ( value: view. value)
180+ return outputs
181+ }
182+
183+ @inline ( __always)
184+ nonisolated package static func makeDebuggableViewList(
185+ view: _GraphValue < Self > ,
186+ inputs: _ViewListInputs
187+ ) -> _ViewListOutputs {
188+ Subgraph . beginTreeElement ( value: view. value, flags: 1 )
189+ defer { Subgraph . endTreeElement ( value: view. value) }
190+ return _makeViewList ( view: view, inputs: inputs)
133191 }
134192}
135193
136194extension _ViewDebug {
137- @inline ( __always)
138- static func instantiateIfNeeded( ) {
139- if !isInitialized {
140- let debugValue = UInt32 ( bitPattern: EnvironmentHelper . int32 ( for: " OPENSWIFTUI_VIEW_DEBUG " ) )
141- properties = Properties ( rawValue: debugValue)
142- isInitialized = true
143- }
144- if !properties. isEmpty {
145- OGSubgraph . setShouldRecordTree ( )
146- }
147- }
148-
149195 // Fix -werror issue
150196 // @available(*, deprecated, message: "To be refactored into View.makeDebuggableView")
151197 @inline ( __always)
@@ -154,42 +200,66 @@ extension _ViewDebug {
154200 inputs: _ViewInputs ,
155201 body: ( _ view: _GraphValue < Value > , _ inputs: _ViewInputs ) -> _ViewOutputs
156202 ) -> _ViewOutputs {
157- var inputs = inputs
158- OGSubgraph . beginTreeElement ( value: view. value, flags: 0 )
159- // FIXME
160- // var outputs = inputs.withEmptyChangedDebugPropertiesInputs { inputs in
161- // body(view, inputs)
162- // }
163- inputs. changedDebugProperties = [ ]
164- var outputs = body ( view, inputs)
165-
166- if OGSubgraph . shouldRecordTree {
167- _ViewDebug. reallyWrap ( & outputs, value: view, inputs: & inputs)
168- OGSubgraph . endTreeElement ( value: view. value)
203+ Subgraph . beginTreeElement ( value: view. value, flags: 0 )
204+ var outputs = body ( view, inputs. withoutChangedDebugProperties)
205+ if Subgraph . shouldRecordTree {
206+ withUnsafePointer ( to: inputs) { pointer in
207+ _ViewDebug. reallyWrap ( & outputs, value: view, inputs: pointer)
208+ }
169209 }
210+ OGSubgraph . endTreeElement ( value: view. value)
170211 return outputs
171212 }
213+ }
214+
215+ // MARK: - ViewDebug + Debug Data
216+
217+ // FIXME
218+ extension Subgraph {
219+ func treeRoot( ) -> Int ? { nil }
220+ }
221+
222+ extension _ViewDebug {
223+ package static func makeDebugData( subgraph: Subgraph ) -> [ _ViewDebug . Data ] {
224+ var result : [ _ViewDebug . Data ] = [ ]
225+ if let rootElement = subgraph. treeRoot ( ) {
226+ appendDebugData ( from: rootElement, to: & result)
227+ }
228+ return result
229+ }
172230
173- private static func reallyWrap < Value > ( _ : inout _ViewOutputs , value : _GraphValue < Value > , inputs _ : UnsafePointer < _ViewInputs > ) {
174- // TODO
231+ private static func appendDebugData ( from element : Int /*AGTreeElement*/ , to result : inout [ _ViewDebug . Data ] ) {
232+ preconditionFailure ( " TODO " )
175233 }
234+ }
176235
177- fileprivate static func appendDebugData( from: Int /*AGTreeElement*/ , to: [ _ViewDebug . Data ] ) { }
236+ extension _ViewDebug {
237+ public static func serializedData( _ viewDebugData: [ _ViewDebug . Data ] ) -> Foundation . Data ? {
238+ let encoder = JSONEncoder ( )
239+ encoder. nonConformingFloatEncodingStrategy = . convertToString( positiveInfinity: " inf " , negativeInfinity: " -inf " , nan: " nan " )
240+ do {
241+ let data = try encoder. encode ( viewDebugData)
242+ return data
243+ } catch {
244+ let dic = [ " error " : error. localizedDescription]
245+ return try ? encoder. encode ( dic)
246+ }
247+ }
178248}
179249
180250// MARK: _ViewDebug.Data
181251
182252extension _ViewDebug . Data : Encodable {
183- public func encode( to encoder: Encoder ) throws {
184- var container : KeyedEncodingContainer < _ViewDebug . Data . CodingKeys > = encoder. container ( keyedBy: _ViewDebug. Data. CodingKeys. self)
185- try container. encode ( serializedProperties ( ) , forKey: . properties)
186- try container. encode ( childData, forKey: . children)
187- }
188-
189253 enum CodingKeys : CodingKey {
190254 case properties
191255 case children
192256 }
257+
258+ public func encode( to encoder: Encoder ) throws {
259+ var container = encoder. container ( keyedBy: CodingKeys . self)
260+ try container. encode ( serializedProperties ( ) , forKey: . properties)
261+ try container. encode ( childData, forKey: . children)
262+ }
193263
194264 private func serializedProperties( ) -> [ SerializedProperty ] {
195265 data. compactMap { key, value -> SerializedProperty ? in
@@ -332,16 +402,37 @@ extension _ViewDebug.Data {
332402 }
333403}
334404
335- private protocol ValueWrapper {
405+ package protocol CustomViewDebugReflectable {
406+ var customViewDebugMirror : Mirror ? { get }
407+ }
408+
409+ package protocol CustomViewDebugValueConvertible {
410+ var viewDebugValue : Any { get }
411+ }
412+
413+ @_spi ( ForOpenSwiftUIOnly)
414+ extension ViewTransform . Item : Encodable {
415+ package func encode( to encoder: any Encoder ) throws {
416+ preconditionFailure ( " TODO " )
417+ }
418+ }
419+
420+ package protocol ValueWrapper {
336421 var wrappedValue : Any ? { get }
337422}
338423
339- extension Optional {
340- var wrappedValue : Any ? {
424+ extension Optional : ValueWrapper {
425+ package var wrappedValue : Any ? {
341426 if case let . some( wrapped) = self {
342427 return wrapped
343428 } else {
344429 return nil
345430 }
346431 }
347432}
433+
434+ @objc
435+ package protocol XcodeViewDebugDataProvider {
436+ @objc
437+ func makeViewDebugData( ) -> Foundation . Data ?
438+ }
0 commit comments