@@ -41,65 +41,123 @@ extension _GraphValue where Value: GraphReusable {
41
41
package static var isTriviallyReusable : Bool { Value . isTriviallyReusable }
42
42
}
43
43
44
- //extension _GraphInputs : GraphReusable {
45
- // package mutating func makeReusable(indirectMap: IndirectAttributeMap)
46
- // package func tryToReuse(by other: _GraphInputs, indirectMap: IndirectAttributeMap, testOnly: Bool) -> Bool
47
- //}
44
+ // MARK: - _GraphInputs + GraphReusable [WIP]
48
45
49
- //extension _GraphInputs {
50
- // private func reuseCustomInputs(by other: _GraphInputs, indirectMap: IndirectAttributeMap, testOnly: Bool) -> Bool {
51
- // Log.graphReuse("Reuse failed: custom input \(Self.self)")
52
- // }
53
- //}
46
+ extension _GraphInputs : GraphReusable {
47
+ package mutating func makeReusable( indirectMap: IndirectAttributeMap ) {
48
+ time. makeReusable ( indirectMap: indirectMap)
49
+ phase. makeReusable ( indirectMap: indirectMap)
50
+ changedDebugProperties. insert ( . phase)
51
+ environment. makeReusable ( indirectMap: indirectMap)
52
+ detachEnvironmentInputs ( )
53
+ changedDebugProperties. insert ( . environment)
54
+ transaction. makeReusable ( indirectMap: indirectMap)
55
+ func project< Input> ( _ type: Input . Type ) where Input: GraphInput {
56
+ guard !Input. isTriviallyReusable else {
57
+ return
58
+ }
59
+ var value = self [ Input . self]
60
+ Input . makeReusable ( indirectMap: indirectMap, value: & value)
61
+ self [ Input . self] = value
62
+ }
63
+ let stack = customInputs [ ReusableInputs . self] . stack
64
+ for value in stack {
65
+ project ( value)
66
+ }
67
+ }
68
+
69
+ package func tryToReuse( by other: _GraphInputs , indirectMap: IndirectAttributeMap , testOnly: Bool ) -> Bool {
70
+ guard time. tryToReuse ( by: other. time, indirectMap: indirectMap, testOnly: testOnly) ,
71
+ phase. tryToReuse ( by: other. phase, indirectMap: indirectMap, testOnly: testOnly) ,
72
+ environment. tryToReuse ( by: other. environment, indirectMap: indirectMap, testOnly: testOnly) ,
73
+ transaction. tryToReuse ( by: other. transaction, indirectMap: indirectMap, testOnly: testOnly)
74
+ else {
75
+ Log . graphReuse ( " Reuse failed: standard inputs " )
76
+ return false
77
+ }
78
+ return reuseCustomInputs ( by: other, indirectMap: indirectMap, testOnly: testOnly)
79
+ }
80
+
81
+ private func reuseCustomInputs( by other: _GraphInputs , indirectMap: IndirectAttributeMap , testOnly: Bool ) -> Bool {
82
+ let reusableInputs = customInputs [ ReusableInputs . self]
83
+ let otherReusableInputs = other. customInputs [ ReusableInputs . self]
84
+ guard reusableInputs. filter == otherReusableInputs. filter else {
85
+ return false
86
+ }
87
+ var reusableInputsArray : [ ObjectIdentifier ] = [ ]
88
+ for value in reusableInputs. stack {
89
+ reusableInputsArray. append ( ObjectIdentifier ( value) )
90
+ }
91
+ var otherReusableInputsArray : [ ObjectIdentifier ] = [ ]
92
+ for value in otherReusableInputs. stack {
93
+ otherReusableInputsArray. append ( ObjectIdentifier ( value) )
94
+ }
95
+ guard reusableInputsArray == otherReusableInputsArray else {
96
+ Log . graphReuse ( " Reuse failed: custom inputs type mismatch " )
97
+ return false
98
+ }
99
+ var ignoredTypes = reusableInputsArray + [ ObjectIdentifier ( ReusableInputs . self) ]
100
+ guard !customInputs. mayNotBeEqual ( to: other. customInputs, ignoredTypes: & ignoredTypes) else { // FIXME
101
+ Log . graphReuse ( " Reuse failed: custom inputs plist equality " )
102
+ return false
103
+ }
104
+ func project< Input> ( _ type: Input . Type ) -> Bool where Input: GraphInput {
105
+ preconditionFailure ( " TODO: Blocked by PropertyList " )
106
+ // WIP
107
+ // Log.graphReuse("Reuse failed: custom input \(Input.self)")
108
+ }
109
+ let stack = reusableInputs. stack
110
+ for value in stack {
111
+ guard project ( value) else {
112
+ return false
113
+ }
114
+ continue
115
+ }
116
+ return true
117
+ }
118
+ }
119
+
120
+ // MARK: - Attribute + GraphReusable
54
121
55
122
extension Attribute : GraphReusable {
56
123
package mutating func makeReusable( indirectMap: IndirectAttributeMap ) {
124
+ let indirect : AnyAttribute
57
125
if let result = indirectMap. map [ identifier] {
58
- identifier = result
126
+ indirect = result
59
127
} else {
60
- let indirect = indirectMap. subgraph. apply {
61
- IndirectAttribute ( source: self )
128
+ indirect = indirectMap. subgraph. apply {
129
+ IndirectAttribute ( source: self ) . identifier
62
130
}
63
- indirectMap. map [ identifier] = indirect. identifier
131
+ indirectMap. map [ identifier] = indirect
64
132
}
133
+ identifier = indirect
65
134
}
66
-
135
+
67
136
package func tryToReuse( by other: Attribute < Value > , indirectMap: IndirectAttributeMap , testOnly: Bool ) -> Bool {
68
- if let result = indirectMap. map [ identifier] {
69
- if testOnly {
70
- return true
71
- } else {
72
- result. source = other. identifier
73
- return true
74
- }
75
- } else {
137
+ guard let result = indirectMap. map [ identifier] else {
76
138
Log . graphReuse ( " Reuse failed: missing indirection for \( Value . self) " )
77
139
return false
78
140
}
141
+ if !testOnly {
142
+ result. source = other. identifier
143
+ }
144
+ return true
79
145
}
80
146
}
81
147
82
- import Foundation
83
- #if canImport(Darwin)
84
- import os. log
85
- #endif
86
-
87
148
private struct EnableGraphReuseLogging : UserDefaultKeyedFeature {
88
149
static var key : String { " org.OpenSwiftUIProject.OpenSwiftUI.GraphReuseLogging " }
150
+
89
151
static var cachedValue : Bool ?
90
152
}
91
153
92
154
extension Log {
93
- #if canImport(Darwin)
94
155
private static let graphReuseLog : Logger = Logger ( subsystem: Log . subsystem, category: " GraphReuse " )
95
- #endif
96
-
156
+
97
157
static func graphReuse( _ message: @autoclosure ( ) -> String ) {
98
- #if canImport(Darwin)
99
158
if EnableGraphReuseLogging . isEnabled {
100
159
let message = message ( )
101
160
graphReuseLog. log ( " \( message) " )
102
161
}
103
- #endif
104
162
}
105
163
}
0 commit comments