From c1cbc1d2815c9433158796d06e75e1d777ba5951 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 7 Oct 2024 00:36:35 +0800 Subject: [PATCH 1/9] Move DynamicProperty into Core --- .../DynamicPropertyBehaviors.swift | 11 -- .../DynamicProperty/DynamicPropertyBox.swift | 18 -- .../DynamicPropertyCache.swift | 114 ------------ .../View/Debug/ChangedBodyProperty.swift | 122 ------------- .../Animation}/Animation.swift | 0 .../Data}/Binding/Binding.swift | 8 +- .../Data}/Binding/BindingOperations.swift | 0 .../Data}/BodyAccessor/BodyAccessor.swift | 4 +- .../Data}/BodyAccessor/BodyAccessorRule.swift | 4 +- .../DynamicProperty/DynamicProperty.swift | 171 +++++++++++++++--- .../DynamicPropertyBuffer.swift | 20 +- .../Data}/State/ConstantLocation.swift | 0 .../Data}/State/FunctionalLocation.swift | 0 .../State/ObservableObjectLocation.swift | 0 .../Data}/State/ObservedObject.swift | 0 .../Data}/State/State.swift | 0 .../Data}/State/StateObject.swift | 0 .../Data}/State/StoredLocation.swift | 3 +- .../Transaction/Transaction+Animation.swift | 0 .../Data/{ => Transaction}/Transaction.swift | 0 .../View/ChangedBodyProperty.swift | 131 ++++++++++++++ Sources/OpenSwiftUICore/View/ViewInputs.swift | 1 + 22 files changed, 297 insertions(+), 310 deletions(-) delete mode 100644 Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyBehaviors.swift delete mode 100644 Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyBox.swift delete mode 100644 Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyCache.swift rename Sources/{OpenSwiftUI/View/Animation/TODO => OpenSwiftUICore/Animation}/Animation.swift (100%) rename Sources/{OpenSwiftUI/Data/Model => OpenSwiftUICore/Data}/Binding/Binding.swift (97%) rename Sources/{OpenSwiftUI/Data/Model => OpenSwiftUICore/Data}/Binding/BindingOperations.swift (100%) rename Sources/{OpenSwiftUI/Core => OpenSwiftUICore/Data}/BodyAccessor/BodyAccessor.swift (83%) rename Sources/{OpenSwiftUI/Core => OpenSwiftUICore/Data}/BodyAccessor/BodyAccessorRule.swift (86%) rename Sources/{OpenSwiftUI/Data/Model => OpenSwiftUICore/Data}/DynamicProperty/DynamicProperty.swift (63%) rename Sources/{OpenSwiftUI/Data/Model => OpenSwiftUICore/Data}/DynamicProperty/DynamicPropertyBuffer.swift (95%) rename Sources/{OpenSwiftUI/Data/Model => OpenSwiftUICore/Data}/State/ConstantLocation.swift (100%) rename Sources/{OpenSwiftUI/Data/Model => OpenSwiftUICore/Data}/State/FunctionalLocation.swift (100%) rename Sources/{OpenSwiftUI/Data/Model => OpenSwiftUICore/Data}/State/ObservableObjectLocation.swift (100%) rename Sources/{OpenSwiftUI/Data/Model => OpenSwiftUICore/Data}/State/ObservedObject.swift (100%) rename Sources/{OpenSwiftUI/Data/Model => OpenSwiftUICore/Data}/State/State.swift (100%) rename Sources/{OpenSwiftUI/Data/Model => OpenSwiftUICore/Data}/State/StateObject.swift (100%) rename Sources/{OpenSwiftUI/Data/Model => OpenSwiftUICore/Data}/State/StoredLocation.swift (98%) rename Sources/{OpenSwiftUI/View => OpenSwiftUICore/Data}/Transaction/Transaction+Animation.swift (100%) rename Sources/OpenSwiftUICore/Data/{ => Transaction}/Transaction.swift (100%) create mode 100644 Sources/OpenSwiftUICore/View/ChangedBodyProperty.swift create mode 100644 Sources/OpenSwiftUICore/View/ViewInputs.swift diff --git a/Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyBehaviors.swift b/Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyBehaviors.swift deleted file mode 100644 index 3380690e..00000000 --- a/Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyBehaviors.swift +++ /dev/null @@ -1,11 +0,0 @@ -// -// DynamicPropertyBehaviors.swift -// OpenSwiftUI -// -// Audited for RELEASE_2021 -// Status: Complete - -struct DynamicPropertyBehaviors: OptionSet { - let rawValue: UInt32 - static var asyncThread: DynamicPropertyBehaviors { .init(rawValue: 1 << 0) } -} diff --git a/Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyBox.swift b/Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyBox.swift deleted file mode 100644 index a9da6438..00000000 --- a/Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyBox.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// DynamicPropertyBox.swift -// OpenSwiftUI -// -// Audited for RELEASE_2021 -// Status: Complete - -protocol DynamicPropertyBox: DynamicProperty { - associatedtype Property: DynamicProperty - func destroy() - mutating func reset() - mutating func update(property: inout Property, phase: _GraphInputs.Phase) -> Bool - func getState(type: Value.Type) -> Binding? -} - -extension DynamicPropertyBox { - func getState(type _: Value.Type) -> Binding? { nil } -} diff --git a/Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyCache.swift b/Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyCache.swift deleted file mode 100644 index 67dab5eb..00000000 --- a/Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyCache.swift +++ /dev/null @@ -1,114 +0,0 @@ -// -// DynamicPropertyCache.swift -// OpenSwiftUI -// -// Audited for RELEASE_2021 -// Status: Complete -// ID: 49D2A32E637CD497C6DE29B8E060A506 - -internal import OpenGraphShims - -// MARK: - DynamicPropertyCache - -struct DynamicPropertyCache { - private static var cache = MutableBox([ObjectIdentifier: Fields]()) - - static func fields(of type: Any.Type) -> Fields { - if let fields = cache.wrappedValue[ObjectIdentifier(type)] { - return fields - } - let fields: Fields - let typeID = OGTypeID(type) - switch typeID.kind { - case .enum, .optional: - var taggedFields: [TaggedFields] = [] - _ = typeID.forEachField(options: [._2, ._4]) { name, offset, fieldType in - var fields: [Field] = [] - let tupleType = OGTupleType(fieldType) - for index in tupleType.indices { - guard let dynamicPropertyType = tupleType.type(at: index) as? DynamicProperty.Type else { - break - } - let offset = tupleType.offset(at: index) - let field = Field(type: dynamicPropertyType, offset: offset, name: name) - fields.append(field) - } - if !fields.isEmpty { - let taggedField = TaggedFields(tag: offset, fields: fields) - taggedFields.append(taggedField) - } - return true - } - fields = Fields(layout: .sum(type, taggedFields)) - case .struct, .tuple: - var fieldArray: [Field] = [] - _ = typeID.forEachField(options: [._2]) { name, offset, fieldType in - guard let dynamicPropertyType = fieldType as? DynamicProperty.Type else { - return true - } - let field = Field(type: dynamicPropertyType, offset: offset, name: name) - fieldArray.append(field) - return true - } - fields = Fields(layout: .product(fieldArray)) - default: - fields = Fields(layout: .product([])) - } - if fields.behaviors.contains(.init(rawValue: 3)) { - Log.runtimeIssues("%s is marked async, but contains properties that require the main thread.", ["\(type)"]) - } - cache.wrappedValue[ObjectIdentifier(type)] = fields - return fields - } -} - -// MARK: - DynamicPropertyCache.Fields - -extension DynamicPropertyCache { - struct Fields { - var layout: Layout - var behaviors: DynamicPropertyBehaviors - - enum Layout { - case product([Field]) - case sum(Any.Type, [TaggedFields]) - } - - init(layout: Layout) { - var behaviors: UInt32 = 0 - switch layout { - case let .product(fields): - for field in fields { - behaviors |= field.type._propertyBehaviors - } - case let .sum(_, taggedFields): - for taggedField in taggedFields { - for field in taggedField.fields { - behaviors |= field.type._propertyBehaviors - } - } - } - self.layout = layout - self.behaviors = .init(rawValue: behaviors) - } - } -} - -// MARK: - DynamicPropertyCache.Field - -extension DynamicPropertyCache { - struct Field { - var type: DynamicProperty.Type - var offset: Int - var name: UnsafePointer? - } -} - -// MARK: - DynamicPropertyCache.TaggedFields - -extension DynamicPropertyCache { - struct TaggedFields { - var tag: Int - var fields: [Field] - } -} diff --git a/Sources/OpenSwiftUI/View/Debug/ChangedBodyProperty.swift b/Sources/OpenSwiftUI/View/Debug/ChangedBodyProperty.swift index 02c89793..71c96d3e 100644 --- a/Sources/OpenSwiftUI/View/Debug/ChangedBodyProperty.swift +++ b/Sources/OpenSwiftUI/View/Debug/ChangedBodyProperty.swift @@ -5,10 +5,6 @@ // Audited for RELEASE_2021 // Status: Complete -#if canImport(Darwin) -internal import OpenGraphShims -import Foundation - // MARK: - printChanges extension View { @@ -40,40 +36,8 @@ extension ViewModifier { } } -func printChangedBodyProperties(of type: Body.Type) { - let properties = changedBodyProperties(of: type) - var result = OGTypeID(type).description - if properties.isEmpty { - result.append(": unchanged.") - } else { - result.append(": \(properties.joined(separator: ", ")) changed.") - } - print(result) -} - // MARK: - logChanges -// Audited for RELEASE_2023 - -#if OPENSWIFTUI_SWIFT_LOG -import Logging - -extension Logger { - static let changeBodyPropertiesLogger = Logger(subsystem: "org.OpenSwiftUIProject.OpenSwiftUI", category: "Changed Body Properties") -} -#else -import os.log - -@available(iOS 14.0, macOS 11, *) -extension Logger { - static let changeBodyPropertiesLogger = Logger(subsystem: "org.OpenSwiftUIProject.OpenSwiftUI", category: "Changed Body Properties") -} - -extension OSLog { - static let changeBodyPropertiesLogger = OSLog(subsystem: "org.OpenSwiftUIProject.OpenSwiftUI", category: "Changed Body Properties") -} -#endif - extension View { /// When called within an invocation of `body` of a view of this type, logs /// the names of the changed dynamic properties that caused the result of @@ -118,89 +82,3 @@ extension ViewModifier { logChangedBodyProperties(of: Self.self) } } - -func logChangedBodyProperties(of type: Body.Type) { - let properties = changedBodyProperties(of: type) - let result = OGTypeID(type).description - if properties.isEmpty { - #if OPENSWIFTUI_SWIFT_LOG - Logger.changeBodyPropertiesLogger.info("\(result): unchanged.") - #else - if #available(iOS 14.0, macOS 11, *) { - Logger.changeBodyPropertiesLogger.info("\(result, privacy: .public): unchanged.") - } else { - os_log("%{public}s: unchanged.", log: .changeBodyPropertiesLogger, type: .info, result) - } - #endif - } else { - #if OPENSWIFTUI_SWIFT_LOG - Logger.changeBodyPropertiesLogger.info("\(result): \(properties.joined(separator: ", ")) changed.") - #else - if #available(iOS 14.0, macOS 11, *) { - Logger.changeBodyPropertiesLogger.info("\(result, privacy: .public): \(properties.joined(separator: ", "), privacy: .public) changed.") - } else { - os_log("%{public}s: %{public}s changed.", log: .changeBodyPropertiesLogger, type: .info, result, properties.joined(separator: ", ")) - } - #endif - } -} - -// MARK: - changedBodyProperties - -func changedBodyProperties(of type: Body.Type) -> [String] { - var index = 0 - repeat { - let options = [ - OGGraph.descriptionFormat.takeUnretainedValue(): "stack/frame", - "frame_index": index, - ] as NSDictionary - guard let description = OGGraph.description(nil, options: options), - let dict = description.takeUnretainedValue() as? [String: Any], - let nodeID = dict["node-id"] as? UInt32, - let selfType = dict["self-type"] as? BodyAccessorRule.Type, - selfType.container == Body.self - else { - index &+= 1 - continue - } - var properties: [String] = [] - let attribute = AnyAttribute(rawValue: nodeID) - let metaProperties = selfType.metaProperties(as: type, attribute: attribute) - if !metaProperties.isEmpty, let inputs = dict["inputs"] as? [[String: Any]] { - for metaProperty in metaProperties { - for input in inputs { - guard let id = input["id"] as? UInt32, - id == metaProperty.1.rawValue, - let changed = input["changed"] as? Bool, - changed - else { - continue - } - properties.append(metaProperty.0) - } - } - } - if let buffer = selfType.buffer(as: type, attribute: attribute) { - let fields = DynamicPropertyCache.fields(of: Body.self) - buffer.applyChanged { offset in - switch fields.layout { - case let .product(fields): - guard let field = fields.first(where: { $0.offset == offset }), - let name = field.name, - let property = String(cString: name, encoding: .utf8) - else { - properties.append("@\(offset)") - return - } - properties.append(property) - case .sum: - properties.append("@\(offset)") - } - } - } - return properties - } while index != 32 - return [] -} - -#endif diff --git a/Sources/OpenSwiftUI/View/Animation/TODO/Animation.swift b/Sources/OpenSwiftUICore/Animation/Animation.swift similarity index 100% rename from Sources/OpenSwiftUI/View/Animation/TODO/Animation.swift rename to Sources/OpenSwiftUICore/Animation/Animation.swift diff --git a/Sources/OpenSwiftUI/Data/Model/Binding/Binding.swift b/Sources/OpenSwiftUICore/Data/Binding/Binding.swift similarity index 97% rename from Sources/OpenSwiftUI/Data/Model/Binding/Binding.swift rename to Sources/OpenSwiftUICore/Data/Binding/Binding.swift index 8a4657a9..a8a560c3 100644 --- a/Sources/OpenSwiftUI/Data/Model/Binding/Binding.swift +++ b/Sources/OpenSwiftUICore/Data/Binding/Binding.swift @@ -6,8 +6,6 @@ // Status: Complete // ID: 5436F2B399369BE3B016147A5F8FE9F2 -@_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore - /// A property wrapper type that can read and write a value owned by a source of /// truth. /// @@ -66,7 +64,7 @@ public struct Binding { /// The transaction captures the information needed to update the view when /// the binding value changes. public var transaction: Transaction - var location: AnyLocation + package var location: AnyLocation private var _value: Value /// Creates a binding with closures that read and write the binding value. @@ -358,7 +356,7 @@ extension Binding: DynamicProperty { // MARK: - Binding Internal API extension Binding { - init(value: Value, location: AnyLocation, transaction: Transaction = Transaction()) { + package init(value: Value, location: AnyLocation, transaction: Transaction = Transaction()) { self.transaction = transaction self.location = location self._value = value @@ -373,7 +371,7 @@ extension Binding { } } - func projecting(_ p: P) -> Binding where P.Base == Value { + package func projecting(_ p: P) -> Binding where P.Base == Value { Binding(value: p.get(base: _value), location: location.projecting(p), transaction: transaction) } } diff --git a/Sources/OpenSwiftUI/Data/Model/Binding/BindingOperations.swift b/Sources/OpenSwiftUICore/Data/Binding/BindingOperations.swift similarity index 100% rename from Sources/OpenSwiftUI/Data/Model/Binding/BindingOperations.swift rename to Sources/OpenSwiftUICore/Data/Binding/BindingOperations.swift diff --git a/Sources/OpenSwiftUI/Core/BodyAccessor/BodyAccessor.swift b/Sources/OpenSwiftUICore/Data/BodyAccessor/BodyAccessor.swift similarity index 83% rename from Sources/OpenSwiftUI/Core/BodyAccessor/BodyAccessor.swift rename to Sources/OpenSwiftUICore/Data/BodyAccessor/BodyAccessor.swift index f364fb75..bd3c6684 100644 --- a/Sources/OpenSwiftUI/Core/BodyAccessor/BodyAccessor.swift +++ b/Sources/OpenSwiftUICore/Data/BodyAccessor/BodyAccessor.swift @@ -7,14 +7,14 @@ internal import OpenGraphShims -protocol BodyAccessor { +package protocol BodyAccessor { associatedtype Container associatedtype Body func updateBody(of container: Container, changed: Bool) } extension BodyAccessor { - func setBody(_ body: () -> Body) { + package func setBody(_ body: () -> Body) { let value = traceRuleBody(Container.self) { OGGraph.withoutUpdate(body) } diff --git a/Sources/OpenSwiftUI/Core/BodyAccessor/BodyAccessorRule.swift b/Sources/OpenSwiftUICore/Data/BodyAccessor/BodyAccessorRule.swift similarity index 86% rename from Sources/OpenSwiftUI/Core/BodyAccessor/BodyAccessorRule.swift rename to Sources/OpenSwiftUICore/Data/BodyAccessor/BodyAccessorRule.swift index 10292b8b..84e0035a 100644 --- a/Sources/OpenSwiftUI/Core/BodyAccessor/BodyAccessorRule.swift +++ b/Sources/OpenSwiftUICore/Data/BodyAccessor/BodyAccessorRule.swift @@ -5,9 +5,9 @@ // Audited for RELEASE_2021 // Status: Complete -internal import OpenGraphShims +package import OpenGraphShims -protocol BodyAccessorRule { +package protocol BodyAccessorRule { static var container: Any.Type { get } static func value(as: Value.Type, attribute: AnyAttribute) -> Value? static func buffer(as: Value.Type, attribute: AnyAttribute) -> _DynamicPropertyBuffer? diff --git a/Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicProperty.swift b/Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicProperty.swift similarity index 63% rename from Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicProperty.swift rename to Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicProperty.swift index 465b9b5a..d2330d15 100644 --- a/Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicProperty.swift +++ b/Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicProperty.swift @@ -2,12 +2,14 @@ // DynamicProperty.swift // OpenSwiftUI // -// Audited for RELEASE_2021 +// Audited for RELEASE_2024 // Status: Complete -// ID: 49D2A32E637CD497C6DE29B8E060A506 +// ID: 49D2A32E637CD497C6DE29B8E060A506 (RELEASE_2021) +// ID: A4C1D658B3717A3062FEFC91A812D6EB (RELEASE_2024) internal import OpenGraphShims -@_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore + +// MARK: - DynamicProperty /// An interface for a stored variable that updates an external property of a /// view. @@ -24,6 +26,8 @@ public protocol DynamicProperty { inputs: inout _GraphInputs ) + /// Describes the static behaviors of the property type. Returns + /// a raw integer value from DynamicPropertyBehaviors. static var _propertyBehaviors: UInt32 { get } /// Updates the underlying value of the stored value. @@ -34,7 +38,45 @@ public protocol DynamicProperty { mutating func update() } -// MARK: Default implementation for DynamicProperty +// MARK: - DynamicPropertyBehaviors + +package struct DynamicPropertyBehaviors: OptionSet { + package let rawValue: UInt32 + package static let allowsAsync = DynamicPropertyBehaviors(rawValue: 1 << 0) + package static let requiresMainThread = DynamicPropertyBehaviors(rawValue: 1 << 1) + + package init(rawValue: UInt32) { + self.rawValue = rawValue + } +} + +// MARK: - DynamicPropertyBox + +package protocol DynamicPropertyBox: DynamicProperty { + associatedtype Property: DynamicProperty + mutating func destroy() + mutating func reset() + mutating func update(property: inout Property, phase: ViewPhase) -> Bool + func getState(type: Value.Type) -> Binding? +} + +// MARK: - Default implementation for DynamicPropertyBox + +extension DynamicPropertyBox { + package func destroy() {} + package func reset() {} + package func getState(type: S.Type = S.self) -> Binding? { nil } +} + +// MARK: - Default implementation for DynamicProperty + +private struct EmbeddedDynamicPropertyBox: DynamicPropertyBox { + typealias Property = Value + func update(property: inout Property, phase _: ViewPhase) -> Bool { + property.update() + return false + } +} extension DynamicProperty { public static func _makeProperty( @@ -55,24 +97,6 @@ extension DynamicProperty { ) } - public static var _propertyBehaviors: UInt32 { 0 } - - public mutating func update() {} -} - -// MARK: - EmbeddedDynamicPropertyBox - -private struct EmbeddedDynamicPropertyBox: DynamicPropertyBox { - typealias Property = Value - func destroy() {} - func reset() {} - func update(property: inout Property, phase _: _GraphInputs.Phase) -> Bool { - property.update() - return false - } -} - -extension DynamicProperty { static func makeEmbeddedProperties( in buffer: inout _DynamicPropertyBuffer, container: _GraphValue, @@ -87,10 +111,109 @@ extension DynamicProperty { baseOffset: fieldOffset ) } + + public mutating func update() {} + + public static var _propertyBehaviors: UInt32 { 0 } } +// MARK: - DynamicPropertyCache [2021] + +package struct DynamicPropertyCache { + package struct Fields { + var layout: Layout + package var behaviors: DynamicPropertyBehaviors + + enum Layout { + case product([Field]) + case sum(Any.Type, [TaggedFields]) + } + + init(layout: Layout) { + var behaviors: UInt32 = 0 + switch layout { + case let .product(fields): + for field in fields { + behaviors |= field.type._propertyBehaviors + } + case let .sum(_, taggedFields): + for taggedField in taggedFields { + for field in taggedField.fields { + behaviors |= field.type._propertyBehaviors + } + } + } + self.layout = layout + self.behaviors = .init(rawValue: behaviors) + } + } + + struct Field { + var type: DynamicProperty.Type + var offset: Int + var name: UnsafePointer? + } + + struct TaggedFields { + var tag: Int + var fields: [Field] + } + + private static var cache = MutableBox([ObjectIdentifier: Fields]()) + + package static func fields(of type: Any.Type) -> Fields { + if let fields = cache.wrappedValue[ObjectIdentifier(type)] { + return fields + } + let fields: Fields + let typeID = OGTypeID(type) + switch typeID.kind { + case .enum, .optional: + var taggedFields: [TaggedFields] = [] + _ = typeID.forEachField(options: [._2, ._4]) { name, offset, fieldType in + var fields: [Field] = [] + let tupleType = OGTupleType(fieldType) + for index in tupleType.indices { + guard let dynamicPropertyType = tupleType.type(at: index) as? DynamicProperty.Type else { + break + } + let offset = tupleType.offset(at: index) + let field = Field(type: dynamicPropertyType, offset: offset, name: name) + fields.append(field) + } + if !fields.isEmpty { + let taggedField = TaggedFields(tag: offset, fields: fields) + taggedFields.append(taggedField) + } + return true + } + fields = Fields(layout: .sum(type, taggedFields)) + case .struct, .tuple: + var fieldArray: [Field] = [] + _ = typeID.forEachField(options: [._2]) { name, offset, fieldType in + guard let dynamicPropertyType = fieldType as? DynamicProperty.Type else { + return true + } + let field = Field(type: dynamicPropertyType, offset: offset, name: name) + fieldArray.append(field) + return true + } + fields = Fields(layout: .product(fieldArray)) + default: + fields = Fields(layout: .product([])) + } + if fields.behaviors.contains(.init(rawValue: 3)) { + Log.runtimeIssues("%s is marked async, but contains properties that require the main thread.", ["\(type)"]) + } + cache.wrappedValue[ObjectIdentifier(type)] = fields + return fields + } +} + +// TO BE AUDITED + extension BodyAccessor { - func makeBody( + package func makeBody( container: _GraphValue, inputs: inout _GraphInputs, fields: DynamicPropertyCache.Fields @@ -124,7 +247,7 @@ extension BodyAccessor { return (_GraphValue(body), buffer) } } - if fields.behaviors.contains(.asyncThread) { + if fields.behaviors.contains(.allowsAsync) { return project(flags: AsyncThreadFlags.self) } else { return project(flags: MainThreadFlags.self) diff --git a/Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyBuffer.swift b/Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicPropertyBuffer.swift similarity index 95% rename from Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyBuffer.swift rename to Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicPropertyBuffer.swift index d3f99412..7fb20ec3 100644 --- a/Sources/OpenSwiftUI/Data/Model/DynamicProperty/DynamicPropertyBuffer.swift +++ b/Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicPropertyBuffer.swift @@ -15,13 +15,13 @@ public struct _DynamicPropertyBuffer { private(set) var size: Int32 private(set) var _count: Int32 - init() { + package init() { buf = nullPtr size = 0 _count = 0 } - init( + package init( fields: DynamicPropertyCache.Fields, container: _GraphValue, inputs: inout _GraphInputs, @@ -31,7 +31,7 @@ public struct _DynamicPropertyBuffer { addFields(fields, container: container, inputs: &inputs, baseOffset: baseOffset) } - mutating func addFields( + package mutating func addFields( _ fields: DynamicPropertyCache.Fields, container: _GraphValue, inputs: inout _GraphInputs, @@ -80,7 +80,7 @@ public struct _DynamicPropertyBuffer { } } - mutating func append(_ box: Box, fieldOffset: Int) { + package mutating func append(_ box: Box, fieldOffset: Int) { let size = MemoryLayout<(Item, Box)>.stride let pointer = allocate(bytes: size) let item = Item(vtable: BoxVTable.self, size: size, fieldOffset: fieldOffset) @@ -94,7 +94,7 @@ public struct _DynamicPropertyBuffer { _count &+= 1 } - func destroy() { + package func destroy() { Swift.precondition(_count >= 0) var count = _count var pointer = buf @@ -111,7 +111,7 @@ public struct _DynamicPropertyBuffer { } } - func reset() { + package func reset() { Swift.precondition(_count >= 0) var count = _count var pointer = buf @@ -124,7 +124,7 @@ public struct _DynamicPropertyBuffer { } } - func getState(type: Value.Type) -> Binding? { + package func getState(type: Value.Type) -> Binding? { Swift.precondition(_count >= 0) var count = _count var pointer = buf @@ -140,7 +140,7 @@ public struct _DynamicPropertyBuffer { return nil } - func update(container: UnsafeMutableRawPointer, phase: _GraphInputs.Phase) -> Bool { + package func update(container: UnsafeMutableRawPointer, phase: _GraphInputs.Phase) -> Bool { Swift.precondition(_count >= 0) var changed = false var count = _count @@ -214,11 +214,11 @@ public struct _DynamicPropertyBuffer { return allocatedBuffer.advanced(by: oldBuffer.distance(to: ptr)) } - func traceMountedProperties(to value: _GraphValue, fields: DynamicPropertyCache.Fields) { + package func traceMountedProperties(to value: _GraphValue, fields: DynamicPropertyCache.Fields) { // TODO: Signpost related } - func applyChanged(to body: (Int) -> Void) { + package func applyChanged(to body: (Int) -> Void) { var index = 0 var pointer = buf while index < _count { diff --git a/Sources/OpenSwiftUI/Data/Model/State/ConstantLocation.swift b/Sources/OpenSwiftUICore/Data/State/ConstantLocation.swift similarity index 100% rename from Sources/OpenSwiftUI/Data/Model/State/ConstantLocation.swift rename to Sources/OpenSwiftUICore/Data/State/ConstantLocation.swift diff --git a/Sources/OpenSwiftUI/Data/Model/State/FunctionalLocation.swift b/Sources/OpenSwiftUICore/Data/State/FunctionalLocation.swift similarity index 100% rename from Sources/OpenSwiftUI/Data/Model/State/FunctionalLocation.swift rename to Sources/OpenSwiftUICore/Data/State/FunctionalLocation.swift diff --git a/Sources/OpenSwiftUI/Data/Model/State/ObservableObjectLocation.swift b/Sources/OpenSwiftUICore/Data/State/ObservableObjectLocation.swift similarity index 100% rename from Sources/OpenSwiftUI/Data/Model/State/ObservableObjectLocation.swift rename to Sources/OpenSwiftUICore/Data/State/ObservableObjectLocation.swift diff --git a/Sources/OpenSwiftUI/Data/Model/State/ObservedObject.swift b/Sources/OpenSwiftUICore/Data/State/ObservedObject.swift similarity index 100% rename from Sources/OpenSwiftUI/Data/Model/State/ObservedObject.swift rename to Sources/OpenSwiftUICore/Data/State/ObservedObject.swift diff --git a/Sources/OpenSwiftUI/Data/Model/State/State.swift b/Sources/OpenSwiftUICore/Data/State/State.swift similarity index 100% rename from Sources/OpenSwiftUI/Data/Model/State/State.swift rename to Sources/OpenSwiftUICore/Data/State/State.swift diff --git a/Sources/OpenSwiftUI/Data/Model/State/StateObject.swift b/Sources/OpenSwiftUICore/Data/State/StateObject.swift similarity index 100% rename from Sources/OpenSwiftUI/Data/Model/State/StateObject.swift rename to Sources/OpenSwiftUICore/Data/State/StateObject.swift diff --git a/Sources/OpenSwiftUI/Data/Model/State/StoredLocation.swift b/Sources/OpenSwiftUICore/Data/State/StoredLocation.swift similarity index 98% rename from Sources/OpenSwiftUI/Data/Model/State/StoredLocation.swift rename to Sources/OpenSwiftUICore/Data/State/StoredLocation.swift index 9e729510..707e3944 100644 --- a/Sources/OpenSwiftUI/Data/Model/State/StoredLocation.swift +++ b/Sources/OpenSwiftUICore/Data/State/StoredLocation.swift @@ -7,8 +7,7 @@ // ID: EBDC911C9EE054BAE3D86F947C24B7C3 internal import OpenGraphShims -internal import COpenSwiftUI -@_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore +internal import COpenSwiftUICore class StoredLocationBase: AnyLocation, Location, @unchecked Sendable { private struct LockedData { diff --git a/Sources/OpenSwiftUI/View/Transaction/Transaction+Animation.swift b/Sources/OpenSwiftUICore/Data/Transaction/Transaction+Animation.swift similarity index 100% rename from Sources/OpenSwiftUI/View/Transaction/Transaction+Animation.swift rename to Sources/OpenSwiftUICore/Data/Transaction/Transaction+Animation.swift diff --git a/Sources/OpenSwiftUICore/Data/Transaction.swift b/Sources/OpenSwiftUICore/Data/Transaction/Transaction.swift similarity index 100% rename from Sources/OpenSwiftUICore/Data/Transaction.swift rename to Sources/OpenSwiftUICore/Data/Transaction/Transaction.swift diff --git a/Sources/OpenSwiftUICore/View/ChangedBodyProperty.swift b/Sources/OpenSwiftUICore/View/ChangedBodyProperty.swift new file mode 100644 index 00000000..a6b938ec --- /dev/null +++ b/Sources/OpenSwiftUICore/View/ChangedBodyProperty.swift @@ -0,0 +1,131 @@ +// +// ChangedBodyProperty.swift +// OpenSwiftUI +// +// Audited for RELEASE_2021 +// Status: Complete + +internal import OpenGraphShims +import Foundation + +// MARK: - changedBodyProperties + +package func changedBodyProperties(of type: Body.Type) -> [String] { + #if canImport(Darwin) + var index = 0 + repeat { + let options = [ + Graph.descriptionFormat.takeUnretainedValue(): "stack/frame", + "frame_index": index, + ] as NSDictionary + guard let description = Graph.description(nil, options: options), + let dict = description.takeUnretainedValue() as? [String: Any], + let nodeID = dict["node-id"] as? UInt32, + let selfType = dict["self-type"] as? BodyAccessorRule.Type, + selfType.container == Body.self + else { + index &+= 1 + continue + } + var properties: [String] = [] + let attribute = AnyAttribute(rawValue: nodeID) + let metaProperties = selfType.metaProperties(as: type, attribute: attribute) + if !metaProperties.isEmpty, let inputs = dict["inputs"] as? [[String: Any]] { + for metaProperty in metaProperties { + for input in inputs { + guard let id = input["id"] as? UInt32, + id == metaProperty.1.rawValue, + let changed = input["changed"] as? Bool, + changed + else { + continue + } + properties.append(metaProperty.0) + } + } + } + if let buffer = selfType.buffer(as: type, attribute: attribute) { + let fields = DynamicPropertyCache.fields(of: Body.self) + buffer.applyChanged { offset in + switch fields.layout { + case let .product(fields): + guard let field = fields.first(where: { $0.offset == offset }), + let name = field.name, + let property = String(cString: name, encoding: .utf8) + else { + properties.append("@\(offset)") + return + } + properties.append(property) + case .sum: + properties.append("@\(offset)") + } + } + } + return properties + } while index != 32 + #endif + return [] +} + +// MARK: - printChanges + +package func printChangedBodyProperties(of type: Body.Type) { + let properties = changedBodyProperties(of: type) + var result = OGTypeID(type).description + if properties.isEmpty { + result.append(": unchanged.") + } else { + result.append(": \(properties.joined(separator: ", ")) changed.") + } + print(result) +} + +// MARK: - logChanges + +// Audited for RELEASE_2023 + +#if OPENSWIFTUI_SWIFT_LOG +import Logging + +extension Logger { + static let changeBodyPropertiesLogger = Logger(subsystem: "org.OpenSwiftUIProject.OpenSwiftUI", category: "Changed Body Properties") +} +#else +import os.log + +@available(iOS 14.0, macOS 11, *) +extension Logger { + static let changeBodyPropertiesLogger = Logger(subsystem: "org.OpenSwiftUIProject.OpenSwiftUI", category: "Changed Body Properties") +} + +extension OSLog { + static let changeBodyPropertiesLogger = OSLog(subsystem: "org.OpenSwiftUIProject.OpenSwiftUI", category: "Changed Body Properties") +} +#endif + +package func logChangedBodyProperties(of type: Body.Type) { + let properties = changedBodyProperties(of: type) + let result = OGTypeID(type).description + if properties.isEmpty { + #if OPENSWIFTUI_SWIFT_LOG + Logger.changeBodyPropertiesLogger.info("\(result): unchanged.") + #else + if #available(iOS 14.0, macOS 11, *) { + Logger.changeBodyPropertiesLogger.info("\(result, privacy: .public): unchanged.") + } else { + os_log("%{public}s: unchanged.", log: .changeBodyPropertiesLogger, type: .info, result) + } + #endif + } else { + #if OPENSWIFTUI_SWIFT_LOG + Logger.changeBodyPropertiesLogger.info("\(result): \(properties.joined(separator: ", ")) changed.") + #else + if #available(iOS 14.0, macOS 11, *) { + Logger.changeBodyPropertiesLogger.info("\(result, privacy: .public): \(properties.joined(separator: ", "), privacy: .public) changed.") + } else { + os_log("%{public}s: %{public}s changed.", log: .changeBodyPropertiesLogger, type: .info, result, properties.joined(separator: ", ")) + } + #endif + } +} diff --git a/Sources/OpenSwiftUICore/View/ViewInputs.swift b/Sources/OpenSwiftUICore/View/ViewInputs.swift new file mode 100644 index 00000000..8221cf3f --- /dev/null +++ b/Sources/OpenSwiftUICore/View/ViewInputs.swift @@ -0,0 +1 @@ +package typealias ViewPhase = _GraphInputs.Phase From fc1323309cc0c518ad8009dd996f19d4a36f4854 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 7 Oct 2024 00:55:51 +0800 Subject: [PATCH 2/9] Fix werror issue --- .github/workflows/compatibility_tests.yml | 4 +-- .github/workflows/ios.yml | 2 +- .github/workflows/macos.yml | 2 +- .github/workflows/ubuntu.yml | 2 +- .github/workflows/wasm.yml | 2 +- Sources/OpenSwiftUI/App/AppGraph.swift | 2 +- Sources/OpenSwiftUI/Core/View/ViewGraph.swift | 14 ++++---- .../Data/Preference/PreferenceBridge.swift | 13 +++---- .../Data/Binding/BindingOperations.swift | 2 -- .../Data/State/ObservableObjectLocation.swift | 1 - .../OpenSwiftUICore/Data/State/State.swift | 1 - .../Data/State/StoredLocation.swift | 36 ++++++++----------- .../OpenSwiftUICore/Graph/ReuseTrace.swift | 2 +- 13 files changed, 37 insertions(+), 46 deletions(-) diff --git a/.github/workflows/compatibility_tests.yml b/.github/workflows/compatibility_tests.yml index 38cb35ec..c18b3656 100644 --- a/.github/workflows/compatibility_tests.yml +++ b/.github/workflows/compatibility_tests.yml @@ -17,7 +17,7 @@ jobs: release: [2024] runs-on: ${{ matrix.os }} env: - OPENSWIFTUI_WERROR: 0 + OPENSWIFTUI_WERROR: 1 OPENGRAPH_ATTRIBUTEGRAPH: 1 OPENSWIFTUI_SWIFT_LOG: 0 OPENSWIFTUI_TARGET_RELEASE: ${{ matrix.release }} @@ -57,7 +57,7 @@ jobs: ios-simulator-name: "iPhone 16 Pro" runs-on: ${{ matrix.os }} env: - OPENSWIFTUI_WERROR: 0 + OPENSWIFTUI_WERROR: 1 OPENGRAPH_ATTRIBUTEGRAPH: 1 OPENSWIFTUI_SWIFT_LOG: 0 OPENSWIFTUI_TARGET_RELEASE: ${{ matrix.release }} diff --git a/.github/workflows/ios.yml b/.github/workflows/ios.yml index 89fbd50a..6b09a0d1 100644 --- a/.github/workflows/ios.yml +++ b/.github/workflows/ios.yml @@ -21,7 +21,7 @@ jobs: ios-simulator-name: "iPhone 16 Pro" runs-on: ${{ matrix.os }} env: - OPENSWIFTUI_WERROR: 0 + OPENSWIFTUI_WERROR: 1 OPENGRAPH_ATTRIBUTEGRAPH: 1 OPENSWIFTUI_COMPATIBILITY_TEST: 0 OPENSWIFTUI_SWIFT_LOG: 0 diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index 893e3311..8c330368 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -17,7 +17,7 @@ jobs: release: [2021, 2024] runs-on: ${{ matrix.os }} env: - OPENSWIFTUI_WERROR: 0 + OPENSWIFTUI_WERROR: 1 OPENGRAPH_ATTRIBUTEGRAPH: 1 OPENSWIFTUI_COMPATIBILITY_TEST: 0 OPENSWIFTUI_SWIFT_LOG: 0 diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 0090ea26..2a81f9c8 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -18,7 +18,7 @@ jobs: continue-on-error: true runs-on: ubuntu-22.04 env: - OPENSWIFTUI_WERROR: 0 + OPENSWIFTUI_WERROR: 1 OPENGRAPH_ATTRIBUTEGRAPH: 0 OPENSWIFTUI_COMPATIBILITY_TEST: 0 OPENSWIFTUI_SWIFT_LOG: 1 diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index 6594b8ef..8510fa71 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -20,7 +20,7 @@ jobs: continue-on-error: true runs-on: ${{ matrix.os }} env: - OPENSWIFTUI_WERROR: 0 + OPENSWIFTUI_WERROR: 1 OPENGRAPH_ATTRIBUTEGRAPH: 0 OPENSWIFTUI_COMPATIBILITY_TEST: 0 OPENSWIFTUI_SWIFT_LOG: 1 diff --git a/Sources/OpenSwiftUI/App/AppGraph.swift b/Sources/OpenSwiftUI/App/AppGraph.swift index 446a143e..11218127 100644 --- a/Sources/OpenSwiftUI/App/AppGraph.swift +++ b/Sources/OpenSwiftUI/App/AppGraph.swift @@ -16,7 +16,7 @@ import WASILibc internal import OpenGraphShims @_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore -final class AppGraph: GraphHost { +package final class AppGraph: GraphHost { static var shared: AppGraph? = nil static var delegateBox: AnyFallbackDelegateBox? = nil diff --git a/Sources/OpenSwiftUI/Core/View/ViewGraph.swift b/Sources/OpenSwiftUI/Core/View/ViewGraph.swift index cb35c6b3..fcf7617e 100644 --- a/Sources/OpenSwiftUI/Core/View/ViewGraph.swift +++ b/Sources/OpenSwiftUI/Core/View/ViewGraph.swift @@ -10,7 +10,7 @@ internal import OpenGraphShims import Foundation @_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore -final class ViewGraph: GraphHost { +package final class ViewGraph: GraphHost { @inline(__always) static var current: ViewGraph { GraphHost.currentHost as! ViewGraph } @@ -190,13 +190,13 @@ final class ViewGraph: GraphHost { // MARK: - Override Methods - override var graphDelegate: GraphDelegate? { delegate } - override var parentHost: GraphHost? { + override package var graphDelegate: GraphDelegate? { delegate } + override package var parentHost: GraphHost? { // TODO: _preferenceBridge nil } - override func instantiateOutputs() { + override package func instantiateOutputs() { #if canImport(Darwin) let outputs = self.data.globalSubgraph.apply { let graphInputs = graphInputs @@ -241,7 +241,7 @@ final class ViewGraph: GraphHost { #endif } - override func uninstantiateOutputs() { + override package func uninstantiateOutputs() { #if canImport(Darwin) removePreferenceOutlets(isInvalidating: false) $rootGeometry.mutateBody( @@ -260,11 +260,11 @@ final class ViewGraph: GraphHost { #endif } - override func timeDidChange() { + override package func timeDidChange() { nextUpdate.views = NextUpdate(time: .infinity) } - override func isHiddenForReuseDidChange() { + override package func isHiddenForReuseDidChange() { // TODO } } diff --git a/Sources/OpenSwiftUI/Data/Preference/PreferenceBridge.swift b/Sources/OpenSwiftUI/Data/Preference/PreferenceBridge.swift index 8831f1f1..775f6219 100644 --- a/Sources/OpenSwiftUI/Data/Preference/PreferenceBridge.swift +++ b/Sources/OpenSwiftUI/Data/Preference/PreferenceBridge.swift @@ -192,11 +192,12 @@ private struct MergePreferenceKeys: Rule, AsyncAttribute { @WeakAttribute var rhs: PreferenceKeys? var value: PreferenceKeys { - var result = lhs - guard let rhs else { - return result - } - // result.merge(rhs) - return result +// var result = lhs +// guard let rhs else { +// return result +// } +// result.merge(rhs) +// return result + fatalError("TODO") } } diff --git a/Sources/OpenSwiftUICore/Data/Binding/BindingOperations.swift b/Sources/OpenSwiftUICore/Data/Binding/BindingOperations.swift index 41525002..8e1b21df 100644 --- a/Sources/OpenSwiftUICore/Data/Binding/BindingOperations.swift +++ b/Sources/OpenSwiftUICore/Data/Binding/BindingOperations.swift @@ -5,8 +5,6 @@ // Audited for RELEASE_2021 // Status: Complete -@_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore - enum BindingOperations {} extension BindingOperations { diff --git a/Sources/OpenSwiftUICore/Data/State/ObservableObjectLocation.swift b/Sources/OpenSwiftUICore/Data/State/ObservableObjectLocation.swift index c84ae0f7..347fff37 100644 --- a/Sources/OpenSwiftUICore/Data/State/ObservableObjectLocation.swift +++ b/Sources/OpenSwiftUICore/Data/State/ObservableObjectLocation.swift @@ -11,7 +11,6 @@ import OpenCombine import Combine #endif internal import COpenSwiftUICore -@_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore struct ObservableObjectLocation: Location where Root: ObservableObject { let base: Root diff --git a/Sources/OpenSwiftUICore/Data/State/State.swift b/Sources/OpenSwiftUICore/Data/State/State.swift index 478a6234..16603c46 100644 --- a/Sources/OpenSwiftUICore/Data/State/State.swift +++ b/Sources/OpenSwiftUICore/Data/State/State.swift @@ -7,7 +7,6 @@ // ID: 08168374F4710A99DCB15B5E8768D632 internal import OpenGraphShims -@_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore /// A property wrapper type that can read and write a value managed by OpenSwiftUI. /// diff --git a/Sources/OpenSwiftUICore/Data/State/StoredLocation.swift b/Sources/OpenSwiftUICore/Data/State/StoredLocation.swift index 707e3944..a7b12a01 100644 --- a/Sources/OpenSwiftUICore/Data/State/StoredLocation.swift +++ b/Sources/OpenSwiftUICore/Data/State/StoredLocation.swift @@ -1,25 +1,20 @@ // // StoredLocation.swift -// OpenSwiftUI +// OpenSwiftUICore // -// Audited for RELEASE_2021 +// Audited for RELEASE_2024 // Status: WIP -// ID: EBDC911C9EE054BAE3D86F947C24B7C3 +// ID: EBDC911C9EE054BAE3D86F947C24B7C3 (RELEASE_2021) +// ID: 4F21368B1C1680817451AC25B55A8D48 (RELEASE_2024) internal import OpenGraphShims internal import COpenSwiftUICore -class StoredLocationBase: AnyLocation, Location, @unchecked Sendable { - private struct LockedData { +package class StoredLocationBase: AnyLocation, Location, @unchecked Sendable { + private struct Data { var currentValue: Value var savedValue: [Value] var cache: LocationProjectionCache - - init(currentValue: Value, savedValue: [Value], cache: LocationProjectionCache = LocationProjectionCache()) { - self.currentValue = currentValue - self.savedValue = savedValue - self.cache = cache - } } fileprivate struct BeginUpdate: GraphMutation { @@ -46,13 +41,12 @@ class StoredLocationBase: AnyLocation, Location, @unchecked Sendab } @AtomicBox - private var data: LockedData - + private var data: Data var _wasRead: Bool - init(initialValue value: Value) { + package init(initialValue value: Value) { _wasRead = false - _data = AtomicBox(wrappedValue: LockedData(currentValue: value, savedValue: [])) + _data = AtomicBox(wrappedValue: Data(currentValue: value, savedValue: [], cache: .init())) super.init() } @@ -74,16 +68,16 @@ class StoredLocationBase: AnyLocation, Location, @unchecked Sendab // MARK: - AnyLocation - override var wasRead: Bool { + override package final var wasRead: Bool { get { _wasRead } set { _wasRead = newValue } } - override func get() -> Value { + override package final func get() -> Value { data.currentValue } - override func set(_ value: Value, transaction: Transaction) { + override package final func set(_ value: Value, transaction: Transaction) { guard !isUpdating else { Log.runtimeIssues("Modifying state during view update, this will cause undefined behavior.") return @@ -116,11 +110,11 @@ class StoredLocationBase: AnyLocation, Location, @unchecked Sendab } } - override func projecting(_ projection: P) -> AnyLocation where Value == P.Base { + override package final func projecting(_ projection: P) -> AnyLocation where Value == P.Base { data.cache.reference(for: projection, on: self) } - override func update() -> (Value, Bool) { + override package func update() -> (Value, Bool) { _wasRead = true return (updateValue, true) } @@ -142,7 +136,7 @@ class StoredLocationBase: AnyLocation, Location, @unchecked Sendab } } -final class StoredLocation: StoredLocationBase, @unchecked Sendable { +package final class StoredLocation: StoredLocationBase, @unchecked Sendable { weak var host: GraphHost? @WeakAttribute var signal: Void? diff --git a/Sources/OpenSwiftUICore/Graph/ReuseTrace.swift b/Sources/OpenSwiftUICore/Graph/ReuseTrace.swift index 90ef4994..18fab386 100644 --- a/Sources/OpenSwiftUICore/Graph/ReuseTrace.swift +++ b/Sources/OpenSwiftUICore/Graph/ReuseTrace.swift @@ -19,8 +19,8 @@ package struct ReuseTrace { @inline(__always) package static func traceReuseFailure(_ name: UnsafePointer) { - guard let recorder else { return } // TODO + // guard let recorder else { return } // OGGraphAddTraceEvent // recorder.graph.addTraceEvent(name) } From 9fab764a567b7b7ed56fe6e7c7bae7afad12c8f8 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 7 Oct 2024 00:57:50 +0800 Subject: [PATCH 3/9] Fix DynamicBody reset logic --- .../Data/DynamicProperty/DynamicProperty.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicProperty.swift b/Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicProperty.swift index d2330d15..d0f96732 100644 --- a/Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicProperty.swift +++ b/Sources/OpenSwiftUICore/Data/DynamicProperty/DynamicProperty.swift @@ -352,10 +352,10 @@ extension DynamicBody: StatefulRule { typealias Value = Accessor.Body mutating func updateValue() { -// if resetSeed != phase.seed { -// links.reset() -// resetSeed = phase.seed -// } + if resetSeed != phase.resetSeed { + links.reset() + resetSeed = phase.resetSeed + } var (container, containerChanged) = $container.changedValue() let linkChanged = withUnsafeMutablePointer(to: &container) { links.update(container: $0, phase: phase) From de547f5eb80894dd64d023410e808b8167d691ff Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 7 Oct 2024 01:00:20 +0800 Subject: [PATCH 4/9] Fix test case build issue --- .../Data/Location/ConstantLocationTests.swift | 2 +- .../Location/FunctionalLocationTests.swift | 0 .../Data/{ => Location}/LocationTests.swift | 0 .../Core/Util/ProtocolDescriptorTests.swift | 32 ------------------- 4 files changed, 1 insertion(+), 33 deletions(-) rename Tests/{OpenSwiftUITests/Core => OpenSwiftUICoreTests}/Data/Location/ConstantLocationTests.swift (93%) rename Tests/{OpenSwiftUITests/Core => OpenSwiftUICoreTests}/Data/Location/FunctionalLocationTests.swift (100%) rename Tests/OpenSwiftUICoreTests/Data/{ => Location}/LocationTests.swift (100%) delete mode 100644 Tests/OpenSwiftUITests/Core/Util/ProtocolDescriptorTests.swift diff --git a/Tests/OpenSwiftUITests/Core/Data/Location/ConstantLocationTests.swift b/Tests/OpenSwiftUICoreTests/Data/Location/ConstantLocationTests.swift similarity index 93% rename from Tests/OpenSwiftUITests/Core/Data/Location/ConstantLocationTests.swift rename to Tests/OpenSwiftUICoreTests/Data/Location/ConstantLocationTests.swift index 3ced97d0..e78d3c7d 100644 --- a/Tests/OpenSwiftUITests/Core/Data/Location/ConstantLocationTests.swift +++ b/Tests/OpenSwiftUICoreTests/Data/Location/ConstantLocationTests.swift @@ -5,7 +5,7 @@ // Created by Kyle on 2023/11/8. // -@testable import OpenSwiftUI +@testable import OpenSwiftUICore import Testing struct ConstantLocationTests { diff --git a/Tests/OpenSwiftUITests/Core/Data/Location/FunctionalLocationTests.swift b/Tests/OpenSwiftUICoreTests/Data/Location/FunctionalLocationTests.swift similarity index 100% rename from Tests/OpenSwiftUITests/Core/Data/Location/FunctionalLocationTests.swift rename to Tests/OpenSwiftUICoreTests/Data/Location/FunctionalLocationTests.swift diff --git a/Tests/OpenSwiftUICoreTests/Data/LocationTests.swift b/Tests/OpenSwiftUICoreTests/Data/Location/LocationTests.swift similarity index 100% rename from Tests/OpenSwiftUICoreTests/Data/LocationTests.swift rename to Tests/OpenSwiftUICoreTests/Data/Location/LocationTests.swift diff --git a/Tests/OpenSwiftUITests/Core/Util/ProtocolDescriptorTests.swift b/Tests/OpenSwiftUITests/Core/Util/ProtocolDescriptorTests.swift deleted file mode 100644 index ba39820c..00000000 --- a/Tests/OpenSwiftUITests/Core/Util/ProtocolDescriptorTests.swift +++ /dev/null @@ -1,32 +0,0 @@ -// -// ProtocolDescriptorTests.swift -// -// -// Created by Kyle on 2023/10/3. -// - -@testable import OpenSwiftUI -import COpenSwiftUI -import Testing - -struct ProtocolDescriptorTests { - @Test - func conformsToProtocolCheck() throws { - struct ContentView: View { - var body: some View { - EmptyView() - } - } - - struct ContentViewModifier: ViewModifier { - func body(content _: Content) -> some View { - EmptyView() - } - } - - #expect(conformsToProtocol(ContentView.self, _OpenSwiftUI_viewProtocolDescriptor())) - #expect(!conformsToProtocol(ContentView.self, _OpenSwiftUI_viewModifierProtocolDescriptor())) - #expect(!conformsToProtocol(ContentViewModifier.self, _OpenSwiftUI_viewProtocolDescriptor())) - #expect(conformsToProtocol(ContentViewModifier.self, _OpenSwiftUI_viewModifierProtocolDescriptor())) - } -} From d477f3bd591a54f7edfb180f3aabe776ccc65c35 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 7 Oct 2024 01:06:32 +0800 Subject: [PATCH 5/9] Fix linux build issue --- Sources/OpenSwiftUICore/Data/Update.swift | 8 ++++---- Sources/OpenSwiftUICore/Graph/GraphHost.swift | 6 ++++++ Sources/OpenSwiftUICore/Graph/GraphInputs.swift | 4 ++++ Sources/OpenSwiftUICore/Graph/GraphReusable.swift | 2 -- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/Sources/OpenSwiftUICore/Data/Update.swift b/Sources/OpenSwiftUICore/Data/Update.swift index 565a3452..072d398f 100644 --- a/Sources/OpenSwiftUICore/Data/Update.swift +++ b/Sources/OpenSwiftUICore/Data/Update.swift @@ -103,16 +103,16 @@ package enum Update { if Thread.isMainThread { body() } else { + #if canImport(Darwin) withoutActuallyEscaping(body) { escapableBody in let context = AnyRuleContext(attribute: AnyOptionalAttribute.current.identifier) MovableLock.syncMain(lock: _lock) { - #if canImport(Darwin) context.update(body: escapableBody) - #else - fatalError("See #39") - #endif } } + #else + fatalError("See #39") + #endif } #endif } diff --git a/Sources/OpenSwiftUICore/Graph/GraphHost.swift b/Sources/OpenSwiftUICore/Graph/GraphHost.swift index 54855c61..d5d98f9c 100644 --- a/Sources/OpenSwiftUICore/Graph/GraphHost.swift +++ b/Sources/OpenSwiftUICore/Graph/GraphHost.swift @@ -112,7 +112,9 @@ open class GraphHost: CustomReflectable { package final var graphInputs: _GraphInputs { data.inputs } package final var globalSubgraph: Subgraph { data.globalSubgraph } package final var rootSubgraph: Subgraph { data.rootSubgraph } + #if canImport(Darwin) private var constants: [ConstantKey: AnyAttribute] = [:] + #endif private(set) package final var isInstantiated: Bool = false package final var hostPreferenceValues: WeakAttribute = WeakAttribute() package final var lastHostPreferencesSeed: VersionSeed = .invalid @@ -220,6 +222,7 @@ open class GraphHost: CustomReflectable { } package final func intern(_ value: T, for type: Any.Type = T.self, id: ConstantID) -> Attribute { + #if canImport(Darwin) if let attribute = constants[ConstantKey(type: type , id: id)] { return Attribute(identifier: attribute) } else { @@ -227,6 +230,9 @@ open class GraphHost: CustomReflectable { constants[ConstantKey(type: type, id: id)] = result.identifier return result } + #else + fatalError("See #39") + #endif } public final var customMirror: Mirror { Mirror(self, children: []) } diff --git a/Sources/OpenSwiftUICore/Graph/GraphInputs.swift b/Sources/OpenSwiftUICore/Graph/GraphInputs.swift index 4f122760..279051d1 100644 --- a/Sources/OpenSwiftUICore/Graph/GraphInputs.swift +++ b/Sources/OpenSwiftUICore/Graph/GraphInputs.swift @@ -96,12 +96,16 @@ public struct _GraphInputs { } package static var invalid: _GraphInputs { + #if canImport(Darwin) _GraphInputs( time: Attribute(identifier: .nil), phase: Attribute(identifier: .nil), environment: Attribute(identifier: .nil), transaction: Attribute(identifier: .nil) ) + #else + fatalError("See #39") + #endif } package subscript(input: T.Type) -> T.Value where T: GraphInput { diff --git a/Sources/OpenSwiftUICore/Graph/GraphReusable.swift b/Sources/OpenSwiftUICore/Graph/GraphReusable.swift index e96f4262..af72198e 100644 --- a/Sources/OpenSwiftUICore/Graph/GraphReusable.swift +++ b/Sources/OpenSwiftUICore/Graph/GraphReusable.swift @@ -8,11 +8,9 @@ package import OpenGraphShims -#if canImport(Darwin) // TODO: Move down to OpenGraph Package package typealias Subgraph = OGSubgraph package typealias Graph = OGGraph -#endif package final class IndirectAttributeMap { #if canImport(Darwin) From 6193756fd1d7074e25214bbf93adc9c0d573bfd2 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 7 Oct 2024 01:28:15 +0800 Subject: [PATCH 6/9] Fix iOS build issue --- Sources/OpenSwiftUI/Core/Render/DisplayLink.swift | 2 ++ .../OpenSwiftUI/Core/View/ViewGraphDelegate.swift | 4 ++-- Sources/OpenSwiftUI/Export.swift | 13 ++++++++++++- .../Integration/UIKit/AnyUIHostingView.swift | 3 +++ .../Integration/UIKit/UIHostingView.swift | 11 ++++++----- 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/Sources/OpenSwiftUI/Core/Render/DisplayLink.swift b/Sources/OpenSwiftUI/Core/Render/DisplayLink.swift index ea882269..953d12cd 100644 --- a/Sources/OpenSwiftUI/Core/Render/DisplayLink.swift +++ b/Sources/OpenSwiftUI/Core/Render/DisplayLink.swift @@ -14,6 +14,8 @@ import UIKit import AppKit #endif +@_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore + final class DisplayLink: NSObject { private weak var host: AnyUIHostingView? private var link: CADisplayLink? diff --git a/Sources/OpenSwiftUI/Core/View/ViewGraphDelegate.swift b/Sources/OpenSwiftUI/Core/View/ViewGraphDelegate.swift index c0d17cea..bde183e7 100644 --- a/Sources/OpenSwiftUI/Core/View/ViewGraphDelegate.swift +++ b/Sources/OpenSwiftUI/Core/View/ViewGraphDelegate.swift @@ -16,11 +16,11 @@ protocol ViewGraphDelegate: GraphDelegate { } extension ViewGraphDelegate { - func updateGraph(body: (GraphHost) -> V) -> V { + public func updateGraph(body: (GraphHost) -> V) -> V { updateViewGraph(body: body) } - func rootTransform() -> ViewTransform { + public func rootTransform() -> ViewTransform { ViewTransform() } } diff --git a/Sources/OpenSwiftUI/Export.swift b/Sources/OpenSwiftUI/Export.swift index 5e1ed03e..bee153f1 100644 --- a/Sources/OpenSwiftUI/Export.swift +++ b/Sources/OpenSwiftUI/Export.swift @@ -1 +1,12 @@ -@_exported import OpenSwiftUICore +@_exported +@_spi(ForOpenSwiftUIOnly) +@_spi(Private) +@_spi(ClarityBoard) +@_spi(Testing) +@_spi(UIFrameworks) +@_spi(RemoteEffects) +@_spi(CustomHoverEffects) +@_spi(DisplayList_ViewSystem) +@_spi(SystemUI) +@_spi(DoNotImport) +import OpenSwiftUICore diff --git a/Sources/OpenSwiftUI/Integration/UIKit/AnyUIHostingView.swift b/Sources/OpenSwiftUI/Integration/UIKit/AnyUIHostingView.swift index 6f1c0b79..d7556d58 100644 --- a/Sources/OpenSwiftUI/Integration/UIKit/AnyUIHostingView.swift +++ b/Sources/OpenSwiftUI/Integration/UIKit/AnyUIHostingView.swift @@ -6,6 +6,9 @@ // Status: Complete #if os(iOS) + +@_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore + protocol AnyUIHostingView: AnyObject { func displayLinkTimer(timestamp: Time, isAsyncThread: Bool) } diff --git a/Sources/OpenSwiftUI/Integration/UIKit/UIHostingView.swift b/Sources/OpenSwiftUI/Integration/UIKit/UIHostingView.swift index 3364d70b..e7c70486 100644 --- a/Sources/OpenSwiftUI/Integration/UIKit/UIHostingView.swift +++ b/Sources/OpenSwiftUI/Integration/UIKit/UIHostingView.swift @@ -7,6 +7,7 @@ // ID: FAF0B683EB49BE9BABC9009857940A1E #if os(iOS) +@_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore import UIKit @available(macOS, unavailable) @@ -102,7 +103,7 @@ open class _UIHostingView: UIView where Content: View { if let displayLink, displayLink.willRender { interval = .zero } else { - interval = renderInterval(timestamp: .now) / UIAnimationDragCoefficient() + interval = renderInterval(timestamp: .systemUptime) / UIAnimationDragCoefficient() } render(interval: interval) allowLayoutWhenNotVisible = false @@ -136,11 +137,11 @@ open class _UIHostingView: UIView where Content: View { private func renderInterval(timestamp: Time) -> Double { if lastRenderTime == .zero || lastRenderTime > timestamp { - lastRenderTime = timestamp - .microseconds(1) + lastRenderTime = timestamp - 1e-6 } let interval = timestamp - lastRenderTime lastRenderTime = timestamp - return interval.seconds + return interval } // TODO @@ -180,11 +181,11 @@ extension _UIHostingView: ViewRendererHost { fatalError("TODO") } - func graphDidChange() { + public func graphDidChange() { // TODO } - func preferencesDidChange() { + public func preferencesDidChange() { // TODO } From c969238df01fe3ab90ef870b5f1ebcd7f880d36a Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 7 Oct 2024 01:38:22 +0800 Subject: [PATCH 7/9] Fix test case issue --- .../Binding/BindingOperationsTests.swift | 2 +- .../Data}/Binding/BindingTests.swift | 4 +- .../DynamicPropertyCacheTests.swift | 2 +- .../DynamicPropertyTests.swift | 2 +- .../Location/FunctionalLocationTests.swift | 2 +- .../Data/Preference/PreferenceKeyTests.swift | 40 +++++++++---------- 6 files changed, 25 insertions(+), 27 deletions(-) rename Tests/{OpenSwiftUITests/Data/Model => OpenSwiftUICoreTests/Data}/Binding/BindingOperationsTests.swift (81%) rename Tests/{OpenSwiftUITests/Data/Model => OpenSwiftUICoreTests/Data}/Binding/BindingTests.swift (99%) rename Tests/{OpenSwiftUITests/Data/Model => OpenSwiftUICoreTests/Data}/DynamicProperty/DynamicPropertyCacheTests.swift (97%) rename Tests/{OpenSwiftUITests/Data/Model => OpenSwiftUICoreTests/Data}/DynamicProperty/DynamicPropertyTests.swift (82%) diff --git a/Tests/OpenSwiftUITests/Data/Model/Binding/BindingOperationsTests.swift b/Tests/OpenSwiftUICoreTests/Data/Binding/BindingOperationsTests.swift similarity index 81% rename from Tests/OpenSwiftUITests/Data/Model/Binding/BindingOperationsTests.swift rename to Tests/OpenSwiftUICoreTests/Data/Binding/BindingOperationsTests.swift index 832c139e..c0db8adf 100644 --- a/Tests/OpenSwiftUITests/Data/Model/Binding/BindingOperationsTests.swift +++ b/Tests/OpenSwiftUICoreTests/Data/Binding/BindingOperationsTests.swift @@ -2,7 +2,7 @@ // BindingOperationsTests.swift // OpenSwiftUITests -@testable import OpenSwiftUI +@testable import OpenSwiftUICore import Testing struct BindingOperationsTests { diff --git a/Tests/OpenSwiftUITests/Data/Model/Binding/BindingTests.swift b/Tests/OpenSwiftUICoreTests/Data/Binding/BindingTests.swift similarity index 99% rename from Tests/OpenSwiftUITests/Data/Model/Binding/BindingTests.swift rename to Tests/OpenSwiftUICoreTests/Data/Binding/BindingTests.swift index a51bdf18..f9010b3d 100644 --- a/Tests/OpenSwiftUITests/Data/Model/Binding/BindingTests.swift +++ b/Tests/OpenSwiftUICoreTests/Data/Binding/BindingTests.swift @@ -2,8 +2,8 @@ // BindingTests.swift // OpenSwiftUITests -@_spi(ForOpenSwiftUIOnly) import OpenSwiftUI -@testable import OpenSwiftUI +@_spi(ForOpenSwiftUIOnly) import OpenSwiftUICore +@testable import OpenSwiftUICore import Testing struct BindingTests { diff --git a/Tests/OpenSwiftUITests/Data/Model/DynamicProperty/DynamicPropertyCacheTests.swift b/Tests/OpenSwiftUICoreTests/Data/DynamicProperty/DynamicPropertyCacheTests.swift similarity index 97% rename from Tests/OpenSwiftUITests/Data/Model/DynamicProperty/DynamicPropertyCacheTests.swift rename to Tests/OpenSwiftUICoreTests/Data/DynamicProperty/DynamicPropertyCacheTests.swift index 47ebfab2..1112e03a 100644 --- a/Tests/OpenSwiftUITests/Data/Model/DynamicProperty/DynamicPropertyCacheTests.swift +++ b/Tests/OpenSwiftUICoreTests/Data/DynamicProperty/DynamicPropertyCacheTests.swift @@ -6,7 +6,7 @@ // import XCTest -@testable import OpenSwiftUI +@testable import OpenSwiftUICore import OpenGraphShims final class DynamicPropertyCacheTests: XCTestCase { diff --git a/Tests/OpenSwiftUITests/Data/Model/DynamicProperty/DynamicPropertyTests.swift b/Tests/OpenSwiftUICoreTests/Data/DynamicProperty/DynamicPropertyTests.swift similarity index 82% rename from Tests/OpenSwiftUITests/Data/Model/DynamicProperty/DynamicPropertyTests.swift rename to Tests/OpenSwiftUICoreTests/Data/DynamicProperty/DynamicPropertyTests.swift index c38e688f..040c4498 100644 --- a/Tests/OpenSwiftUITests/Data/Model/DynamicProperty/DynamicPropertyTests.swift +++ b/Tests/OpenSwiftUICoreTests/Data/DynamicProperty/DynamicPropertyTests.swift @@ -5,7 +5,7 @@ // Created by Kyle on 2023/11/4. // -@testable import OpenSwiftUI +@testable import OpenSwiftUICore import Testing struct DynamicPropertyTests { diff --git a/Tests/OpenSwiftUICoreTests/Data/Location/FunctionalLocationTests.swift b/Tests/OpenSwiftUICoreTests/Data/Location/FunctionalLocationTests.swift index 2d17ab96..698648ac 100644 --- a/Tests/OpenSwiftUICoreTests/Data/Location/FunctionalLocationTests.swift +++ b/Tests/OpenSwiftUICoreTests/Data/Location/FunctionalLocationTests.swift @@ -5,7 +5,7 @@ // Created by Kyle on 2023/11/8. // -@testable import OpenSwiftUI +@testable import OpenSwiftUICore import Testing struct FunctionalLocationTests { diff --git a/Tests/OpenSwiftUICoreTests/Data/Preference/PreferenceKeyTests.swift b/Tests/OpenSwiftUICoreTests/Data/Preference/PreferenceKeyTests.swift index 6cbfc934..eb0c555c 100644 --- a/Tests/OpenSwiftUICoreTests/Data/Preference/PreferenceKeyTests.swift +++ b/Tests/OpenSwiftUICoreTests/Data/Preference/PreferenceKeyTests.swift @@ -6,30 +6,28 @@ import OpenSwiftUICore import Testing struct PreferenceKeyTests { + struct AKey: OpenSwiftUICore.PreferenceKey { + static var defaultValue: Int { 0 } + static func reduce(value: inout Int, nextValue: () -> Int) {} + } + struct BPreference: OpenSwiftUICore.PreferenceKey { + static var defaultValue: Int { 0 } + static func reduce(value: inout Int, nextValue: () -> Int) {} + } + struct CPreferenceKey: OpenSwiftUICore.PreferenceKey { + static var defaultValue: Int { 0 } + static func reduce(value: inout Int, nextValue: () -> Int) {} + } + struct PreferenceKey: OpenSwiftUICore.PreferenceKey { + static var defaultValue: Int { 0 } + static func reduce(value: inout Int, nextValue: () -> Int) {} + } + @Test func readableName() { - struct AKey: OpenSwiftUICore.PreferenceKey { - static var defaultValue: Int { 0 } - static func reduce(value: inout Int, nextValue: () -> Int) {} - } #expect(AKey.readableName == "A") - - struct BPreference: OpenSwiftUICore.PreferenceKey { - static var defaultValue: Int { 0 } - static func reduce(value: inout Int, nextValue: () -> Int) {} - } #expect(BPreference.readableName == "B") - - struct CPreferenceKey: OpenSwiftUICore.PreferenceKey { - static var defaultValue: Int { 0 } - static func reduce(value: inout Int, nextValue: () -> Int) {} - } - #expect(BPreference.readableName == "C") - - struct PreferenceKey: OpenSwiftUICore.PreferenceKey { - static var defaultValue: Int { 0 } - static func reduce(value: inout Int, nextValue: () -> Int) {} - } - #expect(PreferenceKey.readableName == "PreferenceKey") + #expect(CPreferenceKey.readableName == "C") + #expect(PreferenceKey.readableName == "PreferenceKeyTests.PreferenceKey") } } From cb52d2c00468a1541f183ce016bbc3d018d3868a Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 7 Oct 2024 01:47:46 +0800 Subject: [PATCH 8/9] Fix WASI UserDefaults issue --- Sources/OpenSwiftUICore/Semantic/Feature.swift | 17 +++++++++++++---- .../Semantic/FeatureTests.swift | 2 ++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/Sources/OpenSwiftUICore/Semantic/Feature.swift b/Sources/OpenSwiftUICore/Semantic/Feature.swift index 464d50ac..3ab3dd94 100644 --- a/Sources/OpenSwiftUICore/Semantic/Feature.swift +++ b/Sources/OpenSwiftUICore/Semantic/Feature.swift @@ -17,10 +17,12 @@ extension Feature { } package protocol UserDefaultKeyedFeature: Feature { - static var key: String { get } - static var defaultFeatureValue: Bool { get } - static var defaults: UserDefaults { get } - static var cachedValue: Bool? { get set } + static var key: String { get } + static var defaultFeatureValue: Bool { get } + #if !os(WASI) + static var defaults: UserDefaults { get } + #endif + static var cachedValue: Bool? { get set } } extension UserDefaultKeyedFeature { @@ -28,6 +30,10 @@ extension UserDefaultKeyedFeature { if let cachedValue { return cachedValue } else { + #if os(WASI) + cachedValue = defaultFeatureValue + return defaultFeatureValue + #else if defaults.object(forKey: key) != nil { let enable = defaults.bool(forKey: key) cachedValue = enable @@ -36,11 +42,14 @@ extension UserDefaultKeyedFeature { cachedValue = defaultFeatureValue return defaultFeatureValue } + #endif } } package static var defaultFeatureValue: Bool { false } + #if !os(WASI) package static var defaults: UserDefaults { .standard } + #endif } extension UserDefaultKeyedFeature { diff --git a/Tests/OpenSwiftUICoreTests/Semantic/FeatureTests.swift b/Tests/OpenSwiftUICoreTests/Semantic/FeatureTests.swift index 784863c5..0fa327f2 100644 --- a/Tests/OpenSwiftUICoreTests/Semantic/FeatureTests.swift +++ b/Tests/OpenSwiftUICoreTests/Semantic/FeatureTests.swift @@ -21,6 +21,7 @@ struct FeatureTests { #expect(Feature2.defaultValue == true) } + #if !os(WASI) @Test func userDefaults() { struct Feature1: UserDefaultKeyedFeature { @@ -38,4 +39,5 @@ struct FeatureTests { #expect(Feature1.isEnabled == true) UserDefaults.standard.removeObject(forKey: Feature1.key) } + #endif } From 611e2e0531a89842fd4059a40267a87eeda29201 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 7 Oct 2024 01:49:16 +0800 Subject: [PATCH 9/9] Fix extra return issue --- Sources/OpenSwiftUICore/Data/Other/Stack.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/OpenSwiftUICore/Data/Other/Stack.swift b/Sources/OpenSwiftUICore/Data/Other/Stack.swift index e16e8365..9b50d80d 100644 --- a/Sources/OpenSwiftUICore/Data/Other/Stack.swift +++ b/Sources/OpenSwiftUICore/Data/Other/Stack.swift @@ -136,6 +136,5 @@ extension Stack: GraphReusable where Value: GraphReusable { return false } } while true - return false } }