Skip to content

Commit

Permalink
Add OpenSwiftUIBridge target (#167)
Browse files Browse the repository at this point in the history
* Add OpenSwiftUIBridge target

* Update README.md

* Add available check for Darwin OS
  • Loading branch information
Kyle-Ye authored Nov 28, 2024
1 parent 3dd8e6e commit 9f2770f
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 0 deletions.
24 changes: 24 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ let openSwiftUIExtensionTarget = Target.target(
],
swiftSettings: sharedSwiftSettings
)

let bridgeFramework = Context.environment["OPENSWIFTUI_BRIDGE_FRAMEWORK"] ?? "SwiftUI"
let openSwiftUIBridgeTarget = Target.target(
name: "OpenSwiftUIBridge",
dependencies: [
"OpenSwiftUI",
],
sources: ["Bridgeable.swift", bridgeFramework],
swiftSettings: sharedSwiftSettings
)
let OpenSwiftUI_SPITestTarget = Target.testTarget(
name: "OpenSwiftUI_SPITests",
dependencies: [
Expand Down Expand Up @@ -140,6 +150,15 @@ let openSwiftUICompatibilityTestTarget = Target.testTarget(
exclude: ["README.md"],
swiftSettings: sharedSwiftSettings
)
let openSwiftUIBridgeTestTarget = Target.testTarget(
name: "OpenSwiftUIBridgeTests",
dependencies: [
"OpenSwiftUIBridge",
],
exclude: ["README.md"],
sources: ["BridgeableTests.swift", bridgeFramework],
swiftSettings: sharedSwiftSettings
)

let swiftBinPath = Context.environment["_"] ?? "/usr/bin/swift"
let swiftBinURL = URL(fileURLWithPath: swiftBinPath)
Expand All @@ -153,6 +172,7 @@ let package = Package(
.library(name: "OpenSwiftUI", targets: ["OpenSwiftUI", "OpenSwiftUIExtension"]),
// FIXME: This will block xcodebuild build(iOS CI) somehow
// .library(name: "OpenSwiftUI_SPI", targets: ["OpenSwiftUI_SPI"]),
// .library(name: "OpenSwiftUIBridge", targets: ["OpenSwiftUIBridge"])
],
dependencies: [
.package(url: "https://github.com/apple/swift-numerics.git", from: "1.0.2"),
Expand All @@ -179,12 +199,15 @@ let package = Package(
.binaryTarget(name: "CoreServices", path: "PrivateFrameworks/CoreServices.xcframework"),
openSwiftUICoreTarget,
openSwiftUITarget,

openSwiftUIExtensionTarget,
openSwiftUIBridgeTarget,

OpenSwiftUI_SPITestTarget,
openSwiftUICoreTestTarget,
openSwiftUITestTarget,
openSwiftUICompatibilityTestTarget,
openSwiftUIBridgeTestTarget,
]
)

Expand Down Expand Up @@ -234,6 +257,7 @@ if attributeGraphCondition {
openSwiftUICoreTestTarget.addAGSettings()
openSwiftUITestTarget.addAGSettings()
openSwiftUICompatibilityTestTarget.addAGSettings()
openSwiftUIBridgeTestTarget.addAGSettings()
}

#if os(macOS)
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ for various platforms:
> So most of the core feature is only available on Apple platform built with
> AttributeGraph varient.
## Products

- OpenSwiftUI
- A SwiftUI source compatibility framework.
- OpenSwiftUIExtension
- Extensive API collections for OpenSwiftUI & SwiftUI.
- OpenSwiftUIBridge
- A bridge layer for migrating other DSL framework to OpenSwiftUI incrementally and mixing them freely.

## License

See LICENSE file - MIT
Expand Down
16 changes: 16 additions & 0 deletions Sources/OpenSwiftUIBridge/Bridgeable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// Bridgeable.swift
// OpenSwiftUIBridge

import OpenSwiftUI

/// A type that can be converted to and from its counterpart.
public protocol Bridgeable<Counterpart> {
associatedtype Counterpart where Counterpart: Bridgeable, Counterpart.Counterpart == Self

init(_ counterpart: Counterpart)
}

extension Bridgeable {
public var counterpart: Self.Counterpart { .init(self) }
}
78 changes: 78 additions & 0 deletions Sources/OpenSwiftUIBridge/SwiftUI/SwiftUI.Color.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
//
// SwiftUI.Color.swift
// OpenSwiftUIBridge

#if canImport(SwiftUI)
public import SwiftUI
public import OpenSwiftUI

// MARK: Color + Bridgeable

@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
extension SwiftUI.Color: Bridgeable {
public typealias Counterpart = OpenSwiftUI.Color

public init(_ counterpart: Counterpart) {
self.init(OpenSwiftUIColor2SwiftUIColorAdapter(base: counterpart))
}
}

@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
extension OpenSwiftUI.Color: Bridgeable {
public typealias Counterpart = SwiftUI.Color

public init(_ counterpart: Counterpart) {
self.init(SwiftUIColor2OpenSwiftUIColorAdapter(base: counterpart))
}
}

@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
private struct OpenSwiftUIColor2SwiftUIColorAdapter: Hashable, SwiftUI.ShapeStyle {
private let base: OpenSwiftUI.Color

init(base: OpenSwiftUI.Color) {
self.base = base
}

public typealias Resolved = SwiftUI.Color.Resolved

public func resolve(in environment: SwiftUI.EnvironmentValues) -> SwiftUI.Color.Resolved {
.init(base.resolve(in: .init(environment)))
}
}

@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
private struct SwiftUIColor2OpenSwiftUIColorAdapter: Hashable, OpenSwiftUI.ShapeStyle {
private let base: SwiftUI.Color

init(base: SwiftUI.Color) {
self.base = base
}

public typealias Resolved = OpenSwiftUI.Color.Resolved

public func resolve(in environment: OpenSwiftUI.EnvironmentValues) -> OpenSwiftUI.Color.Resolved {
.init(base.resolve(in: .init(environment)))
}
}

// MARK: - Color.Resolved + Bridgeable

@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
extension SwiftUI.Color.Resolved: Bridgeable {
public typealias Counterpart = OpenSwiftUI.Color.Resolved

public init(_ counterpart: Counterpart) {
self.init(colorSpace: .sRGBLinear, red: counterpart.linearRed, green: counterpart.linearGreen, blue: counterpart.linearBlue)
}
}

@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
extension OpenSwiftUI.Color.Resolved: Bridgeable {
public typealias Counterpart = SwiftUI.Color.Resolved

public init(_ counterpart: Counterpart) {
self.init(colorSpace: .sRGBLinear, red: counterpart.linearRed, green: counterpart.linearGreen, blue: counterpart.linearBlue)
}
}
#endif
28 changes: 28 additions & 0 deletions Sources/OpenSwiftUIBridge/SwiftUI/SwiftUI.EnvironmentValues.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// SwiftUI.EnvironmentValues.swift
// OpenSwiftUIBridge

#if canImport(SwiftUI)
public import SwiftUI
public import OpenSwiftUI

// MARK: EnvironmentValues + Bridgeable

extension SwiftUI.EnvironmentValues: Bridgeable {
public typealias Counterpart = OpenSwiftUI.EnvironmentValues

public init(_ counterpart: Counterpart) {
// FIXME
self.init()
}
}

extension OpenSwiftUI.EnvironmentValues: Bridgeable {
public typealias Counterpart = SwiftUI.EnvironmentValues

public init(_ counterpart: Counterpart) {
// FIXME
self.init()
}
}
#endif
Empty file.
42 changes: 42 additions & 0 deletions Tests/OpenSwiftUIBridgeTests/BridgeableTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// BridgeableTests.swift
// OpenSwiftUIBridgeTests

import Testing
import OpenSwiftUIBridge

struct BridgeableTests {
@Test
func example() throws {
struct A1: Bridgeable, Equatable {
typealias Counterpart = A2
var value: Int

init(value: Int) {
self.value = value
}

init(_ counterpart: A2) {
self.value = counterpart.value
}
}

struct A2: Bridgeable, Equatable {
typealias Counterpart = A1
var value: Int

init(value: Int) {
self.value = value
}

init(_ counterpart: A1) {
self.value = counterpart.value
}
}
let a1 = A1(value: 3)
let a2 = A2(value: 3)

#expect(a1.counterpart == a2)
#expect(a2.counterpart == a1)
}
}
7 changes: 7 additions & 0 deletions Tests/OpenSwiftUIBridgeTests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## OpenSwiftUIBridgeTests

Test API of OpenSwiftUIBridge

```swift
import OpenSwiftUIBridge
```
31 changes: 31 additions & 0 deletions Tests/OpenSwiftUIBridgeTests/SwiftUI/SwiftUI.ColorTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//
// SwiftUI.ColorTests.swift
// OpenSwiftUIBridgeTests

#if canImport(SwiftUI)
import Testing
import SwiftUI
import OpenSwiftUI
import OpenSwiftUIBridge

struct SwiftUI_ColorTests {
@Test
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
func color() throws {
let swiftUIWhite = SwiftUI.Color.white
let openSwiftUIWhite = OpenSwiftUI.Color.white
#expect(swiftUIWhite.counterpart.resolve(in: .init()) == openSwiftUIWhite.resolve(in: .init()))
#expect(openSwiftUIWhite.counterpart.resolve(in: .init()) == swiftUIWhite.resolve(in: .init()))
}

@Test
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
func resolved() throws {
let swiftUIWhiteResolved = SwiftUI.Color.Resolved.init(red: 1, green: 1, blue: 1)
let openSwiftUIWhiteResolved = OpenSwiftUI.Color.Resolved.init(red: 1, green: 1, blue: 1)

#expect(swiftUIWhiteResolved.counterpart == openSwiftUIWhiteResolved)
#expect(openSwiftUIWhiteResolved.counterpart == swiftUIWhiteResolved)
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// SwiftUI.EnvironmentValues.swift
// OpenSwiftUIBridgeTests

#if canImport(SwiftUI)
import Testing
import SwiftUI
import OpenSwiftUI
import OpenSwiftUIBridge

struct SwiftUI_EnvironmentValues {
@Test
func example() throws {
var swiftUIEnviromentValues = SwiftUI.EnvironmentValues()
let openSwiftUIEnviromentValues = OpenSwiftUI.EnvironmentValues()
#expect(swiftUIEnviromentValues.colorScheme == .light)
#expect(openSwiftUIEnviromentValues.colorScheme == .light)
swiftUIEnviromentValues.colorScheme = .dark
withKnownIssue {
#expect(swiftUIEnviromentValues.counterpart.colorScheme == .dark)
}
}
}
#endif

0 comments on commit 9f2770f

Please sign in to comment.