Skip to content

Commit 2b39e17

Browse files
authored
Add DynamicBody implementation (#72)
1 parent fa83a71 commit 2b39e17

File tree

4 files changed

+93
-46
lines changed

4 files changed

+93
-46
lines changed

Sources/OpenSwiftUI/Core/Graph/GraphInputs.swift

+7
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,13 @@ public struct _GraphInputs {
9191
extension _GraphInputs {
9292
struct Phase: Equatable {
9393
var value: UInt32
94+
95+
@inline(__always)
96+
var seed: UInt32 {
97+
get { value >> 1 }
98+
// TODO
99+
// set
100+
}
94101
}
95102
}
96103

Sources/OpenSwiftUI/Data/Model/Binding/Binding.swift

+2-2
Original file line numberDiff line numberDiff line change
@@ -336,10 +336,10 @@ extension Binding: DynamicProperty {
336336
} else {
337337
location = LocationBox(location: ScopedLocation(base: property.location))
338338
}
339-
let (value, isUpdated) = location!.update()
339+
let (value, changed) = location!.update()
340340
property.location = location!
341341
property._value = value
342-
return isUpdated ? location!.wasRead : false
342+
return changed ? location!.wasRead : false
343343
}
344344
}
345345

Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicProperty.swift

+73-33
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ private struct MainThreadFlags: RuleThreadFlags {
147147
static var value: OGAttributeTypeFlags { .mainThread }
148148
}
149149

150+
#if canImport(Darwin)
151+
150152
// MARK: - StaticBody
151153

152154
private struct StaticBody<Accessor: BodyAccessor, ThreadFlags: RuleThreadFlags> {
@@ -165,55 +167,43 @@ extension StaticBody: StatefulRule {
165167
func updateValue() {
166168
accessor.updateBody(of: container, changed: true)
167169
}
170+
171+
static var flags: OGAttributeTypeFlags { ThreadFlags.value }
168172
}
169173

170-
extension StaticBody: _AttributeBody {
171-
static var flags: OGAttributeTypeFlags {
172-
ThreadFlags.value
173-
}
174-
}
175-
176-
#if canImport(Darwin)
177-
178174
extension StaticBody: BodyAccessorRule {
179175
static var container: Any.Type {
180176
Accessor.Container.self
181177
}
182178

183-
static func buffer<Value>(as type: Value.Type, attribute: OGAttribute) -> _DynamicPropertyBuffer? {
184-
nil
185-
}
186-
187-
static func value<Value>(as type: Value.Type, attribute: OGAttribute) -> Value? {
188-
guard container == type else {
179+
static func value<Value>(as _: Value.Type, attribute: OGAttribute) -> Value? {
180+
guard container == Value.self else {
189181
return nil
190182
}
191-
return (attribute.info.body.assumingMemoryBound(to: Self.self).pointee.container as! Value)
183+
return unsafeBitCast(attribute.info.body.assumingMemoryBound(to: Self.self).pointee.container, to: Value.self)
184+
}
185+
186+
static func buffer<Value>(as _: Value.Type, attribute _: OGAttribute) -> _DynamicPropertyBuffer? {
187+
nil
192188
}
193189

194-
static func metaProperties<Value>(as type: Value.Type, attribute: OGAttribute) -> [(String, OGAttribute)] {
195-
guard container == type else {
190+
static func metaProperties<Value>(as _: Value.Type, attribute: OGAttribute) -> [(String, OGAttribute)] {
191+
guard container == Value.self else {
196192
return []
197193
}
198194
return [("@self", attribute.info.body.assumingMemoryBound(to: Self.self).pointee._container.identifier)]
199195
}
200196
}
201-
202-
#endif
203-
204197
extension StaticBody: CustomStringConvertible {
205198
var description: String { "\(Accessor.Body.self)" }
206199
}
207200

208201
// MARK: - DynamicBody
209202

210-
// TODO
211203
private struct DynamicBody<Accessor: BodyAccessor, ThreadFlags: RuleThreadFlags> {
212204
let accessor: Accessor
213-
@Attribute
214-
var container: Accessor.Container
215-
@Attribute
216-
var phase: _GraphInputs.Phase
205+
@Attribute var container: Accessor.Container
206+
@Attribute var phase: _GraphInputs.Phase
217207
var links: _DynamicPropertyBuffer
218208
var resetSeed: UInt32
219209

@@ -224,19 +214,69 @@ private struct DynamicBody<Accessor: BodyAccessor, ThreadFlags: RuleThreadFlags>
224214
links: _DynamicPropertyBuffer,
225215
resetSeed: UInt32
226216
) {
227-
fatalError("TODO")
228-
// self.accessor = accessor
229-
// self._container = container
230-
// self._phase = phase
231-
// self.links = links
232-
// self.resetSeed = resetSeed
217+
self.accessor = accessor
218+
self._container = container
219+
self._phase = phase
220+
self.links = links
221+
self.resetSeed = resetSeed
233222
}
234223
}
235224

236225
extension DynamicBody: StatefulRule {
237226
typealias Value = Accessor.Body
238227

239-
func updateValue() {
240-
// TODO
228+
mutating func updateValue() {
229+
if resetSeed != phase.seed {
230+
links.reset()
231+
resetSeed = phase.seed
232+
}
233+
var (container, containerChanged) = $container.changedValue()
234+
let linkChanged = withUnsafeMutablePointer(to: &container) {
235+
links.update(container: $0, phase: phase)
236+
}
237+
let changed = linkChanged || containerChanged || !hasValue
238+
accessor.updateBody(of: container, changed: changed)
239+
}
240+
241+
static var flags: OGAttributeTypeFlags { ThreadFlags.value }
242+
}
243+
244+
extension DynamicBody: ObservedAttribute {
245+
func destroy() { links.destroy() }
246+
}
247+
248+
extension DynamicBody: BodyAccessorRule {
249+
static var container: Any.Type {
250+
Accessor.Container.self
251+
}
252+
253+
static func value<Value>(as _: Value.Type, attribute: OGAttribute) -> Value? {
254+
guard container == Value.self else {
255+
return nil
256+
}
257+
return unsafeBitCast(attribute.info.body.assumingMemoryBound(to: Self.self).pointee.container, to: Value.self)
258+
}
259+
260+
static func buffer<Value>(as _: Value.Type, attribute: OGAttribute) -> _DynamicPropertyBuffer? {
261+
guard container == Value.self else {
262+
return nil
263+
}
264+
return attribute.info.body.assumingMemoryBound(to: Self.self).pointee.links
265+
}
266+
267+
static func metaProperties<Value>(as _: Value.Type, attribute: OGAttribute) -> [(String, OGAttribute)] {
268+
guard container == Value.self else {
269+
return []
270+
}
271+
return [
272+
("@self", attribute.info.body.assumingMemoryBound(to: Self.self).pointee._container.identifier),
273+
("@identity", attribute.info.body.assumingMemoryBound(to: Self.self).pointee._phase.identifier)
274+
]
241275
}
242276
}
277+
278+
extension DynamicBody: CustomStringConvertible {
279+
var description: String { "\(Accessor.Body.self)" }
280+
}
281+
282+
#endif

Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyBuffer.swift

+11-11
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ public struct _DynamicPropertyBuffer {
142142

143143
func update(container: UnsafeMutableRawPointer, phase: _GraphInputs.Phase) -> Bool {
144144
precondition(_count >= 0)
145-
var isUpdated = false
145+
var changed = false
146146
var count = _count
147147
var pointer = buf
148148
while count > 0 {
@@ -155,11 +155,11 @@ public struct _DynamicPropertyBuffer {
155155
phase: phase
156156
)
157157
itemPointer.pointee.lastChanged = updateResult
158-
isUpdated = isUpdated || updateResult
158+
changed = changed || updateResult
159159
pointer += Int(itemPointer.pointee.size)
160160
count &-= 1
161161
}
162-
return isUpdated
162+
return changed
163163
}
164164

165165
private mutating func allocate(bytes: Int) -> UnsafeMutableRawPointer {
@@ -309,11 +309,11 @@ private class BoxVTable<Box: DynamicPropertyBox>: BoxVTableBase {
309309
) -> Bool {
310310
let boxPointer = ptr.assumingMemoryBound(to: Box.self)
311311
let propertyPointer = property.assumingMemoryBound(to: Box.Property.self)
312-
let isUpdated = boxPointer.pointee.update(property: &propertyPointer.pointee, phase: phase)
313-
if isUpdated {
312+
let changed = boxPointer.pointee.update(property: &propertyPointer.pointee, phase: phase)
313+
if changed {
314314
// TODO: OSSignpost
315315
}
316-
return isUpdated
316+
return changed
317317
}
318318

319319
override class func getState<Value>(ptr: UnsafeMutableRawPointer, type: Value.Type) -> Binding<Value>? {
@@ -353,26 +353,26 @@ private class EnumVTable<Enum>: BoxVTableBase {
353353
}
354354

355355
override class func update(ptr: UnsafeMutableRawPointer, property: UnsafeMutableRawPointer, phase: _GraphInputs.Phase) -> Bool {
356-
var isUpdated = false
356+
var changed = false
357357
withUnsafeMutablePointerToEnumCase(of: property.assumingMemoryBound(to: Enum.self)) { tag, _, pointer in
358358
let boxPointer = ptr.assumingMemoryBound(to: EnumBox.self)
359359
if let (activeTag, index) = boxPointer.pointee.active, activeTag != tag {
360360
boxPointer.pointee.cases[index].links.reset()
361361
boxPointer.pointee.active = nil
362-
isUpdated = true
362+
changed = true
363363
}
364364
if boxPointer.pointee.active == nil {
365365
guard let matchedIndex = boxPointer.pointee.cases.firstIndex(where: { $0.tag == tag }) else {
366366
return
367367
}
368368
boxPointer.pointee.active = (tag, matchedIndex)
369-
isUpdated = true
369+
changed = true
370370
}
371371
if let (_, index) = boxPointer.pointee.active {
372-
isUpdated = boxPointer.pointee.cases[index].links.update(container: pointer, phase: phase)
372+
changed = boxPointer.pointee.cases[index].links.update(container: pointer, phase: phase)
373373
}
374374
}
375-
return isUpdated
375+
return changed
376376
}
377377

378378
override class func getState<Value>(ptr: UnsafeMutableRawPointer, type: Value.Type) -> Binding<Value>? {

0 commit comments

Comments
 (0)