Skip to content

Add LegacyApp and Benchmark API #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions Sources/OpenSwiftUI/AppStructure/AppOrganization/LegacyApp.swift
Original file line number Diff line number Diff line change
@@ -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<V: View>: App {
var rootView: V

init() {
fatalError("Not a standalone App.")
}

init(rootView: V) {
self.rootView = rootView
}

var body: some Scene {
WindowGroup { rootView }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
20 changes: 20 additions & 0 deletions Sources/OpenSwiftUI/Internal/Other/EnvironmentHelper.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
}
46 changes: 46 additions & 0 deletions Sources/OpenSwiftUI/Test/TestApp.swift
Original file line number Diff line number Diff line change
@@ -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<V: View>(_ view: V) {
id += 1
testView = AnyView(view.testID(id))
}
}
}
39 changes: 39 additions & 0 deletions Sources/OpenSwiftUI/Test/TestIDView.swift
Original file line number Diff line number Diff line change
@@ -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<Content, ID>: PrimitiveView, UnaryView {
var content: Content
var id: ID

init(content: Content, id: ID) {
self.content = content
self.id = id
}

static func _makeView(view: _GraphValue<TestIDView<Content, ID>>, 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: Hashable>(_ id: ID) -> some View {
TestIDView(content: self, id: id)
}
}
13 changes: 13 additions & 0 deletions Sources/OpenSwiftUI/Test/TestingAppDelegate.swift
Original file line number Diff line number Diff line change
@@ -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
}
10 changes: 10 additions & 0 deletions Sources/OpenSwiftUI/Test/_Benchmark.swift
Original file line number Diff line number Diff line change
@@ -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")
}
}
74 changes: 74 additions & 0 deletions Sources/OpenSwiftUI/Test/_BenchmarkHost.swift
Original file line number Diff line number Diff line change
@@ -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 _: CGFloat, iterations _: Int, delta _: CGFloat, length _: 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
}
}
58 changes: 58 additions & 0 deletions Sources/OpenSwiftUI/Test/_PerformanceTest.swift
Original file line number Diff line number Diff line change
@@ -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
}
}
9 changes: 9 additions & 0 deletions Sources/OpenSwiftUI/Test/_Test.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
public protocol _Test {
func setUpTest()
func tearDownTest()
}

extension _Test {
public func setUpTest() {}
public func tearDownTest() {}
}
11 changes: 11 additions & 0 deletions Sources/OpenSwiftUI/Views/View/internal/ViewRendererHost.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
protocol ViewRendererHost {}

extension ViewRendererHost {
func startProfiling() {
fatalError("TODO")
}

func stopProfiling() {
fatalError("TODO")
}
}
22 changes: 22 additions & 0 deletions Sources/OpenSwiftUIShims/include/OpenSwiftUI_SPI.h
Original file line number Diff line number Diff line change
@@ -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(<UIKit/UIKit.h>)
#import <UIKit/UIKit.h>
@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 */