From dfd4b907eddbef567dfb150144013f6dcc282717 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 9 Jan 2024 17:25:28 +0800 Subject: [PATCH 1/5] Add LegacyApp --- .../AppOrganization/internal/LegacyApp.swift | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Sources/OpenSwiftUI/AppStructure/AppOrganization/internal/LegacyApp.swift diff --git a/Sources/OpenSwiftUI/AppStructure/AppOrganization/internal/LegacyApp.swift b/Sources/OpenSwiftUI/AppStructure/AppOrganization/internal/LegacyApp.swift new file mode 100644 index 00000000..3dae8b11 --- /dev/null +++ b/Sources/OpenSwiftUI/AppStructure/AppOrganization/internal/LegacyApp.swift @@ -0,0 +1,34 @@ +// +// LegacyApp.swift +// OpenSwiftUI +// +// Created by Kyle on 2024/1/9. +// Lastest Version: iOS 15.5 +// Status: Complete +// ID: F8F4CFB3FB453F4ECC15C05B76BCD1E4 + +public enum __App {} + +extension __App { + public static func run(_ rootView: some View) -> Never { + runApp(ShoeboxAdaptor(rootView: rootView)) + } +} + +extension __App { + private struct ShoeboxAdaptor: App { + var rootView: V + + init() { + fatalError("Not a standalone App.") + } + + init(rootView: V) { + self.rootView = rootView + } + + var body: some Scene { + WindowGroup { rootView } + } + } +} From 6bb8b659bcf53f1c1f1d9d3692122e6a3b96e3d6 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 9 Jan 2024 17:25:50 +0800 Subject: [PATCH 2/5] Add TestIDView interface for _TestApp --- .../Internal/Test/TestIDView.swift | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 Sources/OpenSwiftUI/Internal/Test/TestIDView.swift diff --git a/Sources/OpenSwiftUI/Internal/Test/TestIDView.swift b/Sources/OpenSwiftUI/Internal/Test/TestIDView.swift new file mode 100644 index 00000000..d913d03e --- /dev/null +++ b/Sources/OpenSwiftUI/Internal/Test/TestIDView.swift @@ -0,0 +1,39 @@ +// +// TestIDView.swift +// OpenSwiftUI +// +// Created by Kyle on 2023/1/9. +// Lastest Version: iOS 15.5 +// Status: WIP + +internal import OpenGraphShims + +struct TestIDView: PrimitiveView, UnaryView { + var content: Content + var id: ID + + init(content: Content, id: ID) { + self.content = content + self.id = id + } + + static func _makeView(view: _GraphValue>, inputs: _ViewInputs) -> _ViewOutputs { + // Use IdentifiedView here + fatalError("TODO") + } +} + +// TODO +extension TestIDView { + struct IdentifiedView { + @Attribute + var view: TestIDView + var id: ID? + } +} + +extension View { + func testID(_ id: ID) -> some View { + TestIDView(content: self, id: id) + } +} From 9bd3571e866e764dc1dba08113fb3c8627c5b93a Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 9 Jan 2024 19:31:27 +0800 Subject: [PATCH 3/5] Add TestApp --- .../AppOrganization/internal/TestApp.swift | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 Sources/OpenSwiftUI/AppStructure/AppOrganization/internal/TestApp.swift diff --git a/Sources/OpenSwiftUI/AppStructure/AppOrganization/internal/TestApp.swift b/Sources/OpenSwiftUI/AppStructure/AppOrganization/internal/TestApp.swift new file mode 100644 index 00000000..a98370e6 --- /dev/null +++ b/Sources/OpenSwiftUI/AppStructure/AppOrganization/internal/TestApp.swift @@ -0,0 +1,46 @@ +// +// TestApp.swift +// OpenSwiftUI +// +// Created by Kyle on 2024/1/9. +// Lastest Version: iOS 15.5 +// Status: WIP +// ID: A519B5B95CA8FF4E3445832668F0B2D2 + +public struct _TestApp { + public init() { + fatalError("TODO") + } + public func run() -> Never { + fatalError("TODO") + } +} + +extension _TestApp { + struct RootView: View { + @State + var state: StateType + + init() { + fatalError("TODO") + } + + var body: some View { + state.testView + fatalError("TODO") + } + } + +} + +extension _TestApp.RootView { + struct StateType { + var id: Int + var testView: AnyView + + mutating func setTestView(_ view: V) { + id += 1 + testView = AnyView(view.testID(id)) + } + } +} From 348d2e698ce09edc732e6918885d9c3c85740ea8 Mon Sep 17 00:00:00 2001 From: Kyle Date: Tue, 9 Jan 2024 23:20:37 +0800 Subject: [PATCH 4/5] Add _BenchmarkHost --- .../Internal/Other/EnvironmentHelper.swift | 20 +++++ .../Internal/Test/_Benchmark.swift | 3 + .../Internal/Test/_BenchmarkHost.swift | 74 +++++++++++++++++++ Sources/OpenSwiftUI/Internal/Test/_Test.swift | 9 +++ .../View/internal/ViewRendererHost.swift | 11 +++ 5 files changed, 117 insertions(+) create mode 100644 Sources/OpenSwiftUI/Internal/Other/EnvironmentHelper.swift create mode 100644 Sources/OpenSwiftUI/Internal/Test/_Benchmark.swift create mode 100644 Sources/OpenSwiftUI/Internal/Test/_BenchmarkHost.swift create mode 100644 Sources/OpenSwiftUI/Internal/Test/_Test.swift create mode 100644 Sources/OpenSwiftUI/Views/View/internal/ViewRendererHost.swift diff --git a/Sources/OpenSwiftUI/Internal/Other/EnvironmentHelper.swift b/Sources/OpenSwiftUI/Internal/Other/EnvironmentHelper.swift new file mode 100644 index 00000000..defccec9 --- /dev/null +++ b/Sources/OpenSwiftUI/Internal/Other/EnvironmentHelper.swift @@ -0,0 +1,20 @@ +#if canImport(Darwin) +import Darwin +#elseif canImport(Glibc) +import Glibc +#else +#error("Unsupported Platform") +#endif + +enum EnvironmentHelper { + @_transparent + @inline(__always) + static func value(for key: String) -> Bool { + key.withCString { string in + guard let env = getenv(string) else { + return false + } + return atoi(env) != 0 + } + } +} diff --git a/Sources/OpenSwiftUI/Internal/Test/_Benchmark.swift b/Sources/OpenSwiftUI/Internal/Test/_Benchmark.swift new file mode 100644 index 00000000..8ec926c3 --- /dev/null +++ b/Sources/OpenSwiftUI/Internal/Test/_Benchmark.swift @@ -0,0 +1,3 @@ +public protocol _Benchmark: _Test { + func measure(host: _BenchmarkHost) -> [Double] +} diff --git a/Sources/OpenSwiftUI/Internal/Test/_BenchmarkHost.swift b/Sources/OpenSwiftUI/Internal/Test/_BenchmarkHost.swift new file mode 100644 index 00000000..b9cf32bb --- /dev/null +++ b/Sources/OpenSwiftUI/Internal/Test/_BenchmarkHost.swift @@ -0,0 +1,74 @@ +// +// _BenchmarkHost.swift +// OpenSwiftUI +// +// Created by Kyle on 2023/1/9. +// Lastest Version: iOS 15.5 +// Status: Complete +// ID: 3E629D505F0A70F29ACFC010AA42C6E0 + +#if canImport(Darwin) +import CoreGraphics +#elseif os(Linux) +import Foundation +#endif + +#if canImport(QuartzCore) +import QuartzCore +#endif + +private let enableProfiler = EnvironmentHelper.value(for: "OPENSWIFTUI_PROFILE_BENCHMARKS") + +public protocol _BenchmarkHost: AnyObject { + func _renderForTest(interval: Double) + func _renderAsyncForTest(interval: Double) -> Bool + func _performScrollTest(startOffset: CGFloat, iterations: Int, delta: CGFloat, length: CGFloat, completion: (() -> Void)?) +} + +extension _BenchmarkHost { + public func _renderAsyncForTest(interval _: Double) -> Bool { + false + } + + public func _performScrollTest(startOffset _: CoreGraphics.CGFloat, iterations _: Int, delta _: CoreGraphics.CGFloat, length _: CoreGraphics.CGFloat, completion _: (() -> Void)?) {} + + public func measureAction(action: () -> Void) -> Double { + #if canImport(QuartzCore) + let begin = CACurrentMediaTime() + if enableProfiler, + let renderHost = self as? ViewRendererHost { + renderHost.startProfiling() + } + action() + let end = CACurrentMediaTime() + if enableProfiler, + let renderHost = self as? ViewRendererHost { + renderHost.stopProfiling() + } + return end - begin + #else + fatalError("Unsupported Platfrom") + #endif + } + + public func measureRender(interval: Double = 1.0 / 60.0) -> Double { + measureAction { + _renderForTest(interval: interval) + } + } + + public func measureRenders(seconds: Double) -> [Double] { + measureRenders(duration: seconds) + } + + public func measureRenders(duration: Double) -> [Double] { + let minutes = duration / 60.0 + let value = Int(minutes.rounded(.towardZero)) + 1 + let count = max(value, 0) + var results: [Double] = [] + for _ in 0 ..< count { + results.append(measureRender()) + } + return results + } +} diff --git a/Sources/OpenSwiftUI/Internal/Test/_Test.swift b/Sources/OpenSwiftUI/Internal/Test/_Test.swift new file mode 100644 index 00000000..3d312b6a --- /dev/null +++ b/Sources/OpenSwiftUI/Internal/Test/_Test.swift @@ -0,0 +1,9 @@ +public protocol _Test { + func setUpTest() + func tearDownTest() +} + +extension _Test { + public func setUpTest() {} + public func tearDownTest() {} +} diff --git a/Sources/OpenSwiftUI/Views/View/internal/ViewRendererHost.swift b/Sources/OpenSwiftUI/Views/View/internal/ViewRendererHost.swift new file mode 100644 index 00000000..82d4dd38 --- /dev/null +++ b/Sources/OpenSwiftUI/Views/View/internal/ViewRendererHost.swift @@ -0,0 +1,11 @@ +protocol ViewRendererHost {} + +extension ViewRendererHost { + func startProfiling() { + fatalError("TODO") + } + + func stopProfiling() { + fatalError("TODO") + } +} From 6b04c2d635f2ccc3665601e10b730caa2eca4f92 Mon Sep 17 00:00:00 2001 From: Kyle Date: Wed, 10 Jan 2024 00:19:09 +0800 Subject: [PATCH 5/5] Add _BenchmarkHost and _PerformanceTest --- .../{internal => }/LegacyApp.swift | 0 .../AppOrganization/TODO/AppDelegate.swift | 26 +++++---- .../Internal/Test/_Benchmark.swift | 3 - .../internal => Test}/TestApp.swift | 0 .../{Internal => }/Test/TestIDView.swift | 0 .../OpenSwiftUI/Test/TestingAppDelegate.swift | 13 +++++ Sources/OpenSwiftUI/Test/_Benchmark.swift | 10 ++++ .../{Internal => }/Test/_BenchmarkHost.swift | 2 +- .../OpenSwiftUI/Test/_PerformanceTest.swift | 58 +++++++++++++++++++ .../{Internal => }/Test/_Test.swift | 0 .../include/OpenSwiftUI_SPI.h | 22 +++++++ 11 files changed, 118 insertions(+), 16 deletions(-) rename Sources/OpenSwiftUI/AppStructure/AppOrganization/{internal => }/LegacyApp.swift (100%) delete mode 100644 Sources/OpenSwiftUI/Internal/Test/_Benchmark.swift rename Sources/OpenSwiftUI/{AppStructure/AppOrganization/internal => Test}/TestApp.swift (100%) rename Sources/OpenSwiftUI/{Internal => }/Test/TestIDView.swift (100%) create mode 100644 Sources/OpenSwiftUI/Test/TestingAppDelegate.swift create mode 100644 Sources/OpenSwiftUI/Test/_Benchmark.swift rename Sources/OpenSwiftUI/{Internal => }/Test/_BenchmarkHost.swift (91%) create mode 100644 Sources/OpenSwiftUI/Test/_PerformanceTest.swift rename Sources/OpenSwiftUI/{Internal => }/Test/_Test.swift (100%) create mode 100644 Sources/OpenSwiftUIShims/include/OpenSwiftUI_SPI.h diff --git a/Sources/OpenSwiftUI/AppStructure/AppOrganization/internal/LegacyApp.swift b/Sources/OpenSwiftUI/AppStructure/AppOrganization/LegacyApp.swift similarity index 100% rename from Sources/OpenSwiftUI/AppStructure/AppOrganization/internal/LegacyApp.swift rename to Sources/OpenSwiftUI/AppStructure/AppOrganization/LegacyApp.swift diff --git a/Sources/OpenSwiftUI/AppStructure/AppOrganization/TODO/AppDelegate.swift b/Sources/OpenSwiftUI/AppStructure/AppOrganization/TODO/AppDelegate.swift index 85b15867..8662c9e1 100644 --- a/Sources/OpenSwiftUI/AppStructure/AppOrganization/TODO/AppDelegate.swift +++ b/Sources/OpenSwiftUI/AppStructure/AppOrganization/TODO/AppDelegate.swift @@ -7,9 +7,20 @@ // Status: WIP // ID: 4475FD12FD59DEBA453321BD91F6EA04 -#if os(iOS) || os(tvOS) +#if os(iOS) import UIKit -class AppDelegate: UIResponder { +typealias DelegateBaseClass = UIResponder +#elseif os(macOS) +import AppKit +typealias DelegateBaseClass = NSResponder +#else +import Foundation +// FIXME: Temporarily use NSObject as a placeholder +typealias DelegateBaseClass = NSObject +#endif + +class AppDelegate: DelegateBaseClass { + #if os(iOS) var fallbackDelegate: UIApplicationDelegate? // WIP @@ -26,14 +37,5 @@ class AppDelegate: UIResponder { let canSelfRespond = AppDelegate.instancesRespond(to: aSelector) return canDelegateRespond || canSelfRespond } + #endif } -#elseif os(watchOS) -import WatchKit -class AppDelegate { - -} -#elseif os(macOS) -import AppKit -class AppDelegate { -} -#endif diff --git a/Sources/OpenSwiftUI/Internal/Test/_Benchmark.swift b/Sources/OpenSwiftUI/Internal/Test/_Benchmark.swift deleted file mode 100644 index 8ec926c3..00000000 --- a/Sources/OpenSwiftUI/Internal/Test/_Benchmark.swift +++ /dev/null @@ -1,3 +0,0 @@ -public protocol _Benchmark: _Test { - func measure(host: _BenchmarkHost) -> [Double] -} diff --git a/Sources/OpenSwiftUI/AppStructure/AppOrganization/internal/TestApp.swift b/Sources/OpenSwiftUI/Test/TestApp.swift similarity index 100% rename from Sources/OpenSwiftUI/AppStructure/AppOrganization/internal/TestApp.swift rename to Sources/OpenSwiftUI/Test/TestApp.swift diff --git a/Sources/OpenSwiftUI/Internal/Test/TestIDView.swift b/Sources/OpenSwiftUI/Test/TestIDView.swift similarity index 100% rename from Sources/OpenSwiftUI/Internal/Test/TestIDView.swift rename to Sources/OpenSwiftUI/Test/TestIDView.swift diff --git a/Sources/OpenSwiftUI/Test/TestingAppDelegate.swift b/Sources/OpenSwiftUI/Test/TestingAppDelegate.swift new file mode 100644 index 00000000..4bf5b8d0 --- /dev/null +++ b/Sources/OpenSwiftUI/Test/TestingAppDelegate.swift @@ -0,0 +1,13 @@ +#if os(iOS) +import UIKit +#elseif os(macOS) +import AppKit +#endif + +class TestingAppDelegate: DelegateBaseClass { + static var performanceTests: [_PerformanceTest]? + + #if os(iOS) + static var connectCallback: ((UIWindow) -> Void)? + #endif +} diff --git a/Sources/OpenSwiftUI/Test/_Benchmark.swift b/Sources/OpenSwiftUI/Test/_Benchmark.swift new file mode 100644 index 00000000..80ed5457 --- /dev/null +++ b/Sources/OpenSwiftUI/Test/_Benchmark.swift @@ -0,0 +1,10 @@ +public protocol _Benchmark: _Test { + func measure(host: _BenchmarkHost) -> [Double] +} + +extension _TestApp { + public func runBenchmarks(_ benchmarks: [_Benchmark]) -> Never { + let _ = RootView() + fatalError("TODO") + } +} diff --git a/Sources/OpenSwiftUI/Internal/Test/_BenchmarkHost.swift b/Sources/OpenSwiftUI/Test/_BenchmarkHost.swift similarity index 91% rename from Sources/OpenSwiftUI/Internal/Test/_BenchmarkHost.swift rename to Sources/OpenSwiftUI/Test/_BenchmarkHost.swift index b9cf32bb..a7f219a0 100644 --- a/Sources/OpenSwiftUI/Internal/Test/_BenchmarkHost.swift +++ b/Sources/OpenSwiftUI/Test/_BenchmarkHost.swift @@ -30,7 +30,7 @@ extension _BenchmarkHost { false } - public func _performScrollTest(startOffset _: CoreGraphics.CGFloat, iterations _: Int, delta _: CoreGraphics.CGFloat, length _: CoreGraphics.CGFloat, completion _: (() -> Void)?) {} + public func _performScrollTest(startOffset _: CGFloat, iterations _: Int, delta _: CGFloat, length _: CGFloat, completion _: (() -> Void)?) {} public func measureAction(action: () -> Void) -> Double { #if canImport(QuartzCore) diff --git a/Sources/OpenSwiftUI/Test/_PerformanceTest.swift b/Sources/OpenSwiftUI/Test/_PerformanceTest.swift new file mode 100644 index 00000000..76a19e4b --- /dev/null +++ b/Sources/OpenSwiftUI/Test/_PerformanceTest.swift @@ -0,0 +1,58 @@ +// +// _PerformanceTest.swift +// OpenSwiftUI +// +// Created by Kyle on 2023/1/9. +// Lastest Version: iOS 15.5 +// Status: WIP + +#if os(iOS) +import UIKit +#elseif os(macOS) +import AppKit +#endif + +internal import OpenSwiftUIShims + +public protocol _PerformanceTest: _Test { + var name: String { get } + func runTest(host: _BenchmarkHost, options: [AnyHashable: Any]) +} + +extension __App { + public static func _registerPerformanceTests(_ tests: [_PerformanceTest]) { + TestingAppDelegate.performanceTests = tests + } +} + +extension _TestApp { + public func runPerformanceTests(_ tests: [_PerformanceTest]) -> Never { + fatalError("TODO") + } +} + +extension _BenchmarkHost { + public func _started(test: _PerformanceTest) { + #if os(iOS) + UIApplication.shared.startedTest(test.name) + #else + fatalError("TODO") + #endif + } + + public func _finished(test: _PerformanceTest) { + #if os(iOS) + UIApplication.shared.finishedTest(test.name) + #else + fatalError("TODO") + #endif + } + + public func _failed(test: _PerformanceTest) { + #if os(iOS) + UIApplication.shared.failedTest(test.name, withFailure: nil) + #else + fatalError("TODO") + #endif + } +} diff --git a/Sources/OpenSwiftUI/Internal/Test/_Test.swift b/Sources/OpenSwiftUI/Test/_Test.swift similarity index 100% rename from Sources/OpenSwiftUI/Internal/Test/_Test.swift rename to Sources/OpenSwiftUI/Test/_Test.swift diff --git a/Sources/OpenSwiftUIShims/include/OpenSwiftUI_SPI.h b/Sources/OpenSwiftUIShims/include/OpenSwiftUI_SPI.h new file mode 100644 index 00000000..5ca9230a --- /dev/null +++ b/Sources/OpenSwiftUIShims/include/OpenSwiftUI_SPI.h @@ -0,0 +1,22 @@ +// +// OpenSwiftUI_SPI.h +// +// +// Created by Kyle on 2024/1/9. +// + +#ifndef OpenSwiftUI_SPI_h +#define OpenSwiftUI_SPI_h + +#if __has_include() +#import +@interface UIApplication (OpenSwiftUI_SPI) +- (void)startedTest:(nullable NSString *)name; +- (void)finishedTest:(nullable NSString *)name; +- (void)failedTest:(nullable NSString *)name withFailure:(nullable NSError*)failure; +@end +#else + +#endif + +#endif /* OpenSwiftUI_SPI_h */