Skip to content

Commit

Permalink
Merge pull request #32 from p-x9/feature/non-apple-platform
Browse files Browse the repository at this point in the history
Support for non-apple platform
  • Loading branch information
p-x9 authored Feb 2, 2024
2 parents 8977c1f + 10ee736 commit 654b88c
Show file tree
Hide file tree
Showing 12 changed files with 452 additions and 303 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,17 @@ jobs:

- name: Test
run: swift test

linux-test:
name: Linux Test
runs-on: ubuntu-latest
steps:
- name: Install Swift
uses: slashmo/install-swift@v0.4.0
with:
version: swift-5.9-RELEASE

- uses: actions/checkout@v4

- name: Test
run: swift test
5 changes: 4 additions & 1 deletion AssociatedObject.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,12 @@ Pod::Spec.new do |s|

s.prepare_command = 'swift build -c release && cp -f .build/release/AssociatedObjectPlugin ./Binary'

s.source_files = "Sources/AssociatedObject/AssociatedObject.swift", 'Sources/AssociatedObjectC/**/*.{c,h,m,swift}'
s.source_files = "Sources/AssociatedObject/**/*.{c,h,m,swift}", 'Sources/AssociatedObjectC/**/*.{c,h,m,swift}'
s.swift_versions = "5.9"

# CocoaPods do not support Linux
# s.dependency "ObjectAssociation", "0.5.0"

s.preserve_paths = ["Binary/AssociatedObjectPlugin"]
s.pod_target_xcconfig = {
'OTHER_SWIFT_FLAGS' => [
Expand Down
9 changes: 9 additions & 0 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,15 @@
"version" : "0.2.2"
}
},
{
"identity" : "swift-object-association",
"kind" : "remoteSourceControl",
"location" : "https://github.com/p-x9/swift-object-association.git",
"state" : {
"revision" : "93806cfecae1f198c894ed5585b93aff0e2d1f5a",
"version" : "0.5.0"
}
},
{
"identity" : "swift-snapshot-testing",
"kind" : "remoteSourceControl",
Expand Down
15 changes: 14 additions & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ let package = Package(
url: "https://github.com/p-x9/swift-literal-type-inference.git",
from: "0.1.0"
),
.package(
url: "https://github.com/p-x9/swift-object-association.git",
from: "0.5.0"
),
.package(
url: "https://github.com/pointfreeco/swift-macro-testing.git",
from: "0.2.2"
Expand All @@ -35,7 +39,16 @@ let package = Package(
name: "AssociatedObject",
dependencies: [
"AssociatedObjectC",
"AssociatedObjectPlugin"
"AssociatedObjectPlugin",
.product(
name: "ObjectAssociation",
package: "swift-object-association",
condition: .when(
platforms: [
.linux, .openbsd, .windows, .android
]
)
)
]
),
.target(
Expand Down
22 changes: 17 additions & 5 deletions Sources/AssociatedObject/AssociatedObject.swift
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
@_exported import ObjectiveC

#if canImport(AssociatedObjectC)
@_exported import AssociatedObjectC
#endif


#if canImport(ObjectiveC)

@_exported import ObjectiveC
public typealias Policy = objc_AssociationPolicy

#elseif canImport(ObjectAssociation)

@_exported import ObjectAssociation
public typealias Policy = swift_AssociationPolicy

#endif


@attached(peer, names: arbitrary)
@attached(accessor)
public macro AssociatedObject(
_ policy: objc_AssociationPolicy
_ policy: Policy
) = #externalMacro(
module: "AssociatedObjectPlugin",
type: "AssociatedObjectMacro"
Expand All @@ -16,7 +28,7 @@ public macro AssociatedObject(
@attached(peer, names: arbitrary)
@attached(accessor)
public macro AssociatedObject(
_ policy: objc_AssociationPolicy,
_ policy: Policy,
key: Any
) = #externalMacro(
module: "AssociatedObjectPlugin",
Expand All @@ -25,7 +37,7 @@ public macro AssociatedObject(

@attached(accessor)
public macro _AssociatedObject(
_ policy: objc_AssociationPolicy
_ policy: Policy
) = #externalMacro(
module: "AssociatedObjectPlugin",
type: "AssociatedObjectMacro"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
//
//

#if canImport(ObjectiveC)

import ObjectiveC

/// Extension for objc_AssociationPolicy to provide a more Swift-friendly interface.
Expand Down Expand Up @@ -47,3 +49,5 @@ extension objc_AssociationPolicy {
}
}
}

#endif
43 changes: 43 additions & 0 deletions Sources/AssociatedObject/Extension/swift_AssociationPolicy+.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// swift_AssociationPolicy+.swift
//
//
// Created by p-x9 on 2024/01/29.
//
//

#if canImport(ObjectAssociation)

import ObjectAssociation

/// Extension for swift_AssociationPolicy to provide a more Swift-friendly interface.
extension swift_AssociationPolicy {
/// Represents the atomicity options for associated objects.
public enum Atomicity {
/// Indicates that the associated object should be stored atomically.
case atomic
/// Indicates that the associated object should be stored non-atomically.
case nonatomic
}

/// A property wrapper that corresponds to `.SWIFT_ASSOCIATION_ASSIGN` policy.
public static var assign: Self { .SWIFT_ASSOCIATION_ASSIGN }

/// A property wrapper that corresponds to `.SWIFT_ASSOCIATION_WEAK` policy.
public static var weak: Self { .SWIFT_ASSOCIATION_WEAK }

/// Create an association policy for retaining an associated object with the specified atomicity.
///
/// - Parameter atomicity: The desired atomicity for the associated object.
/// - Returns: The appropriate association policy for retaining with the specified atomicity.
public static func retain(_ atomicity: Atomicity) -> Self {
switch atomicity {
case .atomic:
return .SWIFT_ASSOCIATION_RETAIN
case .nonatomic:
return .SWIFT_ASSOCIATION_RETAIN_NONATOMIC
}
}
}

#endif
50 changes: 50 additions & 0 deletions Sources/AssociatedObject/functions.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// functions.swift
//
//
// Created by p-x9 on 2024/01/28.
//
//

#if canImport(ObjectiveC)
import ObjectiveC
#elseif canImport(ObjectAssociation)
import ObjectAssociation
#else
#warning("Current platform is not supported")
#endif


public func getAssociatedObject(
_ object: AnyObject,
_ key: UnsafeRawPointer
) -> Any? {
#if canImport(ObjectiveC)
objc_getAssociatedObject(object, key)
#elseif canImport(ObjectAssociation)
ObjectAssociation.getAssociatedObject(object, key)
#endif
}


public func setAssociatedObject(
_ object: AnyObject,
_ key: UnsafeRawPointer,
_ value: Any?,
_ policy: Policy = .retain(.nonatomic)
) {
#if canImport(ObjectiveC)
objc_setAssociatedObject(
object,
key,
value,
policy
)
#elseif canImport(ObjectAssociation)
ObjectAssociation.setAssociatedObject(
object,
key,
value
)
#endif
}
91 changes: 46 additions & 45 deletions Sources/AssociatedObjectPlugin/AssociatedObjectMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ extension AssociatedObjectMacro: PeerMacro {
let flagName = "__associated_\(identifier.trimmed)IsSet"
let flagDecl = VariableDeclSyntax(
attributes: [
.attribute("@_AssociatedObject(.OBJC_ASSOCIATION_ASSIGN)")
.attribute("@_AssociatedObject(.retain(.nonatomic))")
],
bindingSpecifier: .identifier("var"),
bindings: PatternBindingListSyntax {
Expand Down Expand Up @@ -176,15 +176,18 @@ extension AssociatedObjectMacro: AccessorMacro {
return []
}

guard case let .argumentList(arguments) = node.arguments,
let firstElement = arguments.first?.expression,
let policy = firstElement.as(ExprSyntax.self) else {
guard case let .argumentList(arguments) = node.arguments else {
return []
}

var policy: ExprSyntax = ".retain(.nonatomic)"
if let firstElement = arguments.first?.expression,
let specifiedPolicy = firstElement.as(ExprSyntax.self) {
policy = specifiedPolicy
}

var associatedKey: ExprSyntax = "Self.__associated_\(identifier.trimmed)Key"
if case let .argumentList(arguments) = node.arguments,
let element = arguments.first(where: { $0.label?.text == "key" }),
if let element = arguments.first(where: { $0.label?.text == "key" }),
let customKey = element.expression.as(ExprSyntax.self) {
// Provide store key from outside the macro
associatedKey = "&\(customKey)"
Expand Down Expand Up @@ -225,7 +228,7 @@ extension AssociatedObjectMacro {
policy: ExprSyntax,
defaultValue: ExprSyntax?
) -> AccessorDeclSyntax {
let varTypeWithoutOptional = if let type = type.as(ImplicitlyUnwrappedOptionalTypeSyntax.self) {
let typeWithoutOptional = if let type = type.as(ImplicitlyUnwrappedOptionalTypeSyntax.self) {
type.wrappedType
} else {
type
Expand All @@ -234,51 +237,49 @@ extension AssociatedObjectMacro {
return AccessorDeclSyntax(
accessorSpecifier: .keyword(.get),
body: CodeBlockSyntax {
if let defaultValue {
if type.isOptional {
"""
if !self.__associated_\(identifier.trimmed)IsSet {
let value: \(type.trimmed) = \(defaultValue.trimmed)
objc_setAssociatedObject(
self,
\(associatedKey),
value,
\(policy.trimmed)
)
self.__associated_\(identifier.trimmed)IsSet = true
return value
} else {
return objc_getAssociatedObject(
self,
\(associatedKey)
) as! \(varTypeWithoutOptional.trimmed)
}
"""
if let defaultValue, type.isOptional {
"""
if !self.__associated_\(identifier.trimmed)IsSet {
let value: \(type.trimmed) = \(defaultValue.trimmed)
setAssociatedObject(
self,
\(associatedKey),
value,
\(policy.trimmed)
)
self.__associated_\(identifier.trimmed)IsSet = true
return value
} else {
"""
if let value = objc_getAssociatedObject(
return getAssociatedObject(
self,
\(associatedKey)
) as? \(varTypeWithoutOptional.trimmed) {
return value
} else {
let value: \(type.trimmed) = \(defaultValue.trimmed)
objc_setAssociatedObject(
self,
\(associatedKey),
value,
\(policy.trimmed)
)
return value
}
"""
) as! \(typeWithoutOptional.trimmed)
}
"""
} else if let defaultValue {
"""
if let value = getAssociatedObject(
self,
\(associatedKey)
) as? \(typeWithoutOptional.trimmed) {
return value
} else {
let value: \(type.trimmed) = \(defaultValue.trimmed)
setAssociatedObject(
self,
\(associatedKey),
value,
\(policy.trimmed)
)
return value
}
"""
} else {
"""
objc_getAssociatedObject(
getAssociatedObject(
self,
\(associatedKey)
) as? \(varTypeWithoutOptional.trimmed)
) as? \(typeWithoutOptional.trimmed)
?? \(defaultValue ?? "nil")
"""
}
Expand Down Expand Up @@ -324,7 +325,7 @@ extension AssociatedObjectMacro {
}

"""
objc_setAssociatedObject(
setAssociatedObject(
self,
\(associatedKey),
newValue,
Expand Down
Loading

0 comments on commit 654b88c

Please sign in to comment.