A Swift macro package that automatically generates property-wrapper-equivalent macros from property wrapper types.
Macrofy simplifies the creation of property wrapper macros by automatically generating the macro expansion logic for your property wrappers.
You can simply add @macrofy to your @propertyWrapper declaration to generate a macro that can be used in place of your property wrapper in code!
In Swift 6 language mode, property wrappers introduce problematic behavior due to their inability to support Sendable types.
Since Apple has not yet introduced a solution for this problem, a natural solution is to pursue macro usage in place of property wrappers.
Unfortunately, macros are more difficult and verbose to implement than property wrappers.
This library hopes to make that process easier by using your existing property wrappers to generate equivalent macros.
- Automatic macro generation: Transform any property wrapper into a macro with a single annotation (and a little boilerplate)
- Drop-in equivalency: The macro expansion implementation adjusts to your property wrapper type, considering settability and project values
- Flexible customization: Protocol-based APIs allow for further customization and fine-tuning when needed
Even if you have an existing package, this can be useful to create the boilerplate needed for macros.
$ swift package init --type macroFor the sake of this example, we assume the following structure:
MyWrapper/ # SPM package
└── Sources/
├── MyWrapperMacro # library target
└── MyWrapperMacroInternal # macro targetLocation: MyWrapperMacroInternal
Note
Currently, this must be done in a macro target (NOT a library target).
In the future, we may aim to allow for the macro to be used in library targets, but this requires further development.
import Macrofy
// swift syntax imports are needed for the macro
import SwiftSyntax
import SwiftSyntaxMacros
@macrofy
@propertyWrapper
public struct MyWrapper<Value: Sendable>: Sendable {
public init(wrappedValue: Value) {
self.wrappedValue = wrappedValue
}
public let wrappedValue: Value
}
// Generates `MyWrapperMacro`Location: MyWrapperMacroInternal
import SwiftCompilerPlugin
import SwiftSyntaxMacros
@main
struct MyWrapperMacroPlugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [MyWrapperMacro.self]
}Location: MyWrapperMacro
@attached(peer, names: prefixed(_), prefixed(`$`))
@attached(accessor, names: named(get), named(set))
public macro MyWrapper(
_ arguments: Any...
) = #externalMacro(module: "MyWrapperMacroInternal", type: "MyWrapperMacro")import MyWrapperMacro
final class Service: Sendable {
@MyWrapper var value: String = "I'm a macro!"
}This project is licensed under the MIT License - see the LICENSE file for details.