Skip to content

Commit f840804

Browse files
committed
Update ViewDebug
1 parent 0f9c299 commit f840804

File tree

3 files changed

+179
-77
lines changed

3 files changed

+179
-77
lines changed

Sources/OpenSwiftUICore/View/Debug/ViewDebug.swift

Lines changed: 169 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,16 @@
44
//
55
// Audited for iOS 18.0
66
// Status: WIP
7+
// ID: 5A14269649C60F846422EA0FA4C5E535 (SwiftUI)
8+
// ID: 43DA1754B0518AF1D72B90677BF266DB (SwiftUICore)
79

810
public import Foundation
911
import OpenGraphShims
1012
import OpenSwiftUI_SPI
1113

14+
/// Namespace for view debug information.
1215
public 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)
7379
extension _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

136194
extension _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

182252
extension _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,39 @@ 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+
#if canImport(Darwin)
435+
@objc
436+
package protocol XcodeViewDebugDataProvider {
437+
@objc
438+
func makeViewDebugData() -> Foundation.Data?
439+
}
440+
#endif

Sources/OpenSwiftUICore/View/Graph/ViewGraph.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ package final class ViewGraph: GraphHost {
217217
if let preferenceBridge {
218218
preferenceBridge.wrapInputs(&inputs)
219219
}
220-
_ViewDebug.instantiateIfNeeded() // FIXME
220+
_ViewDebug.initialize(inputs: &inputs)
221221
if _VariableFrameDurationIsSupported() {
222222
if !inputs.base.options.contains(.supportsVariableFrameDuration) {
223223
inputs.base.options.formUnion(.supportsVariableFrameDuration)

Sources/OpenSwiftUICore/View/Input/ViewInputs.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,15 @@ public struct _ViewInputs {
217217
@available(*, unavailable)
218218
extension _ViewInputs: Sendable {}
219219

220+
extension _ViewInputs {
221+
@inline(__always)
222+
var withoutChangedDebugProperties: _ViewInputs {
223+
var copy = self
224+
copy.changedDebugProperties = []
225+
return copy
226+
}
227+
}
228+
220229

221230
// FIXME: TO BE REMOVED
222231

0 commit comments

Comments
 (0)