Skip to content

Commit dccdf5a

Browse files
authored
Reintroduce conditional import (#108)
* Reintroduce conditional import Not all platforms have Observation enabled in their official releases at this time, for example SwiftWasm. * wip * wip * wip * Fix * wip * wip * wip * wip * wip
1 parent 81b311a commit dccdf5a

File tree

6 files changed

+133
-79
lines changed

6 files changed

+133
-79
lines changed

.github/workflows/ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,37 @@ jobs:
3131
run: make test-compatibility
3232
if: ${{ matrix.config == 'debug' }}
3333

34+
linux:
35+
name: Linux
36+
strategy:
37+
matrix:
38+
swift:
39+
- '6.0'
40+
runs-on: ubuntu-latest
41+
container: swift:${{ matrix.swift }}
42+
steps:
43+
- uses: actions/checkout@v4
44+
- name: Build
45+
run: swift build
46+
47+
wasm:
48+
name: Wasm
49+
runs-on: ubuntu-latest
50+
steps:
51+
- uses: actions/checkout@v4
52+
- uses: bytecodealliance/actions/wasmtime/setup@v1
53+
- name: Install Swift and Swift SDK for WebAssembly
54+
run: |
55+
PREFIX=/opt/swift
56+
set -ex
57+
curl -f -o /tmp/swift.tar.gz "https://download.swift.org/swift-6.0.2-release/ubuntu2204/swift-6.0.2-RELEASE/swift-6.0.2-RELEASE-ubuntu22.04.tar.gz"
58+
sudo mkdir -p $PREFIX; sudo tar -xzf /tmp/swift.tar.gz -C $PREFIX --strip-component 1
59+
$PREFIX/usr/bin/swift sdk install https://github.com/swiftwasm/swift/releases/download/swift-wasm-6.0.2-RELEASE/swift-wasm-6.0.2-RELEASE-wasm32-unknown-wasi.artifactbundle.zip --checksum 6ffedb055cb9956395d9f435d03d53ebe9f6a8d45106b979d1b7f53358e1dcb4
60+
echo "$PREFIX/usr/bin" >> $GITHUB_PATH
61+
62+
- name: Build
63+
run: swift build --swift-sdk wasm32-unknown-wasi -Xlinker -z -Xlinker stack-size=$((1024 * 1024))
64+
3465
check-macro-compatibility:
3566
name: Check Macro Compatibility
3667
runs-on: macos-latest
Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
@_exported import Observation
1+
#if canImport(Observation)
2+
@_exported import Observation
3+
#else
4+
@available(macOS 14, iOS 17, watchOS 10, tvOS 17, *)
5+
public protocol Observable {}
6+
#endif

Sources/PerceptionCore/Internal/ThreadLocal.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import Foundation
1313

1414
struct _ThreadLocal {
1515
#if os(WASI)
16-
static var value: UnsafeMutableRawPointer?
16+
static nonisolated(unsafe) var value: UnsafeMutableRawPointer?
1717
#else
1818
static var value: UnsafeMutableRawPointer? {
1919
get { Thread.current.threadDictionary[Key()] as! UnsafeMutableRawPointer? }

Sources/PerceptionCore/PerceptionRegistrar.swift

Lines changed: 89 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,11 @@ public struct PerceptionRegistrar: Sendable {
2424
/// of a type.
2525
public init(isPerceptionCheckingEnabled: Bool = PerceptionCore.isPerceptionCheckingEnabled) {
2626
if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *), !isObservationBeta {
27-
self._rawValue = AnySendable(ObservationRegistrar())
27+
#if canImport(Observation)
28+
self._rawValue = AnySendable(ObservationRegistrar())
29+
#else
30+
self._rawValue = AnySendable(_PerceptionRegistrar())
31+
#endif
2832
} else {
2933
self._rawValue = AnySendable(_PerceptionRegistrar())
3034
}
@@ -33,47 +37,51 @@ public struct PerceptionRegistrar: Sendable {
3337
#endif
3438
}
3539

36-
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
37-
private var registrar: ObservationRegistrar {
38-
self._rawValue.base as! ObservationRegistrar
39-
}
40+
#if canImport(Observation)
41+
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
42+
private var registrar: ObservationRegistrar {
43+
self._rawValue.base as! ObservationRegistrar
44+
}
45+
#endif
4046

4147
private var perceptionRegistrar: _PerceptionRegistrar {
4248
self._rawValue.base as! _PerceptionRegistrar
4349
}
4450
}
4551

46-
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
47-
extension PerceptionRegistrar {
48-
public func access<Subject: Observable, Member>(
49-
_ subject: Subject,
50-
keyPath: KeyPath<Subject, Member>,
51-
fileID: StaticString = #fileID,
52-
filePath: StaticString = #filePath,
53-
line: UInt = #line,
54-
column: UInt = #column
55-
) {
56-
self.registrar.access(subject, keyPath: keyPath)
57-
}
52+
#if canImport(Observation)
53+
@available(iOS 17, macOS 14, tvOS 17, watchOS 10, *)
54+
extension PerceptionRegistrar {
55+
public func access<Subject: Observable, Member>(
56+
_ subject: Subject,
57+
keyPath: KeyPath<Subject, Member>,
58+
fileID: StaticString = #fileID,
59+
filePath: StaticString = #filePath,
60+
line: UInt = #line,
61+
column: UInt = #column
62+
) {
63+
self.registrar.access(subject, keyPath: keyPath)
64+
}
5865

59-
public func withMutation<Subject: Observable, Member, T>(
60-
of subject: Subject, keyPath: KeyPath<Subject, Member>, _ mutation: () throws -> T
61-
) rethrows -> T {
62-
try self.registrar.withMutation(of: subject, keyPath: keyPath, mutation)
63-
}
66+
public func withMutation<Subject: Observable, Member, T>(
67+
of subject: Subject, keyPath: KeyPath<Subject, Member>, _ mutation: () throws -> T
68+
) rethrows -> T {
69+
try self.registrar.withMutation(of: subject, keyPath: keyPath, mutation)
70+
}
6471

65-
public func willSet<Subject: Observable, Member>(
66-
_ subject: Subject, keyPath: KeyPath<Subject, Member>
67-
) {
68-
self.registrar.willSet(subject, keyPath: keyPath)
69-
}
72+
public func willSet<Subject: Observable, Member>(
73+
_ subject: Subject, keyPath: KeyPath<Subject, Member>
74+
) {
75+
self.registrar.willSet(subject, keyPath: keyPath)
76+
}
7077

71-
public func didSet<Subject: Observable, Member>(
72-
_ subject: Subject, keyPath: KeyPath<Subject, Member>
73-
) {
74-
self.registrar.didSet(subject, keyPath: keyPath)
78+
public func didSet<Subject: Observable, Member>(
79+
_ subject: Subject, keyPath: KeyPath<Subject, Member>
80+
) {
81+
self.registrar.didSet(subject, keyPath: keyPath)
82+
}
7583
}
76-
}
84+
#endif
7785

7886
extension PerceptionRegistrar {
7987
@_disfavoredOverload
@@ -93,17 +101,19 @@ extension PerceptionRegistrar {
93101
column: column
94102
)
95103
#endif
96-
if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *), !isObservationBeta {
97-
func `open`<T: Observable>(_ subject: T) {
98-
self.registrar.access(
99-
subject,
100-
keyPath: unsafeDowncast(keyPath, to: KeyPath<T, Member>.self)
101-
)
102-
}
103-
if let subject = subject as? any Observable {
104-
return open(subject)
104+
#if canImport(Observation)
105+
if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *), !isObservationBeta {
106+
func `open`<T: Observable>(_ subject: T) {
107+
self.registrar.access(
108+
subject,
109+
keyPath: unsafeDowncast(keyPath, to: KeyPath<T, Member>.self)
110+
)
111+
}
112+
if let subject = subject as? any Observable {
113+
return open(subject)
114+
}
105115
}
106-
}
116+
#endif
107117
self.perceptionRegistrar.access(subject, keyPath: keyPath)
108118
}
109119

@@ -113,18 +123,20 @@ extension PerceptionRegistrar {
113123
keyPath: KeyPath<Subject, Member>,
114124
_ mutation: () throws -> T
115125
) rethrows -> T {
116-
if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *), !isObservationBeta,
117-
let subject = subject as? any Observable
118-
{
119-
func `open`<S: Observable>(_ subject: S) throws -> T {
120-
return try self.registrar.withMutation(
121-
of: subject,
122-
keyPath: unsafeDowncast(keyPath, to: KeyPath<S, Member>.self),
123-
mutation
124-
)
126+
#if canImport(Observation)
127+
if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *), !isObservationBeta,
128+
let subject = subject as? any Observable
129+
{
130+
func `open`<S: Observable>(_ subject: S) throws -> T {
131+
return try self.registrar.withMutation(
132+
of: subject,
133+
keyPath: unsafeDowncast(keyPath, to: KeyPath<S, Member>.self),
134+
mutation
135+
)
136+
}
137+
return try open(subject)
125138
}
126-
return try open(subject)
127-
}
139+
#endif
128140
return try self.perceptionRegistrar.withMutation(of: subject, keyPath: keyPath, mutation)
129141
}
130142

@@ -133,17 +145,19 @@ extension PerceptionRegistrar {
133145
_ subject: Subject,
134146
keyPath: KeyPath<Subject, Member>
135147
) {
136-
if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *), !isObservationBeta,
137-
let subject = subject as? any Observable
138-
{
139-
func `open`<S: Observable>(_ subject: S) {
140-
return self.registrar.willSet(
141-
subject,
142-
keyPath: unsafeDowncast(keyPath, to: KeyPath<S, Member>.self)
143-
)
148+
#if canImport(Observation)
149+
if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *), !isObservationBeta,
150+
let subject = subject as? any Observable
151+
{
152+
func `open`<S: Observable>(_ subject: S) {
153+
return self.registrar.willSet(
154+
subject,
155+
keyPath: unsafeDowncast(keyPath, to: KeyPath<S, Member>.self)
156+
)
157+
}
158+
return open(subject)
144159
}
145-
return open(subject)
146-
}
160+
#endif
147161
return self.perceptionRegistrar.willSet(subject, keyPath: keyPath)
148162
}
149163

@@ -152,17 +166,19 @@ extension PerceptionRegistrar {
152166
_ subject: Subject,
153167
keyPath: KeyPath<Subject, Member>
154168
) {
155-
if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *), !isObservationBeta,
156-
let subject = subject as? any Observable
157-
{
158-
func `open`<S: Observable>(_ subject: S) {
159-
return self.registrar.didSet(
160-
subject,
161-
keyPath: unsafeDowncast(keyPath, to: KeyPath<S, Member>.self)
162-
)
169+
#if canImport(Observation)
170+
if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *), !isObservationBeta,
171+
let subject = subject as? any Observable
172+
{
173+
func `open`<S: Observable>(_ subject: S) {
174+
return self.registrar.didSet(
175+
subject,
176+
keyPath: unsafeDowncast(keyPath, to: KeyPath<S, Member>.self)
177+
)
178+
}
179+
return open(subject)
163180
}
164-
return open(subject)
165-
}
181+
#endif
166182
return self.perceptionRegistrar.didSet(subject, keyPath: keyPath)
167183
}
168184
}

Sources/PerceptionCore/PerceptionTracking.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -209,9 +209,11 @@ public func withPerceptionTracking<T>(
209209
_ apply: () -> T,
210210
onChange: @autoclosure () -> @Sendable () -> Void
211211
) -> T {
212-
if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *), !isObservationBeta {
213-
return withObservationTracking(apply, onChange: onChange())
214-
}
212+
#if canImport(Observation)
213+
if #available(iOS 17, macOS 14, tvOS 17, watchOS 10, *), !isObservationBeta {
214+
return withObservationTracking(apply, onChange: onChange())
215+
}
216+
#endif
215217
let (result, accessList) = generateAccessList(apply)
216218
if let accessList {
217219
PerceptionTracking._installTracking(accessList, onChange: onChange())

Sources/PerceptionMacros/PerceptibleMacro.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ extension PerceptibleMacro: ExtensionMacro {
308308
}
309309

310310
let decl: DeclSyntax = """
311-
extension \(raw: type.trimmedDescription): \(raw: qualifiedConformanceName), Observation.Observable {}
311+
extension \(raw: type.trimmedDescription): \(raw: qualifiedConformanceName), Observable {}
312312
"""
313313
let ext = decl.cast(ExtensionDeclSyntax.self)
314314

0 commit comments

Comments
 (0)