Skip to content
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
10 changes: 10 additions & 0 deletions Sources/StructTransaction/Source.swift
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@

/**
Available only for structs
*/
@attached(
extension,
conformances: DetectingType,
Expand All @@ -9,6 +12,13 @@
)
public macro Detecting() = #externalMacro(module: "StructTransactionMacros", type: "WriterMacro")

/**
Available only for member functions.
Marker Macro that indicates if the function will be exported into Accessing struct.
*/
@attached(peer)
public macro Exporting() = #externalMacro(module: "StructTransactionMacros", type: "MarkerMacro")

/**
Use ``Detecting()`` macro to adapt struct
*/
Expand Down
14 changes: 14 additions & 0 deletions Sources/StructTransactionMacros/MarkerMacro.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import SwiftCompilerPlugin
import SwiftSyntax
import SwiftSyntaxBuilder
import SwiftSyntaxMacros

public struct MarkerMacro: Macro {

}

extension MarkerMacro: PeerMacro {
public static func expansion(of node: SwiftSyntax.AttributeSyntax, providingPeersOf declaration: some SwiftSyntax.DeclSyntaxProtocol, in context: some SwiftSyntaxMacros.MacroExpansionContext) throws -> [SwiftSyntax.DeclSyntax] {
[]
}
}
3 changes: 2 additions & 1 deletion Sources/StructTransactionMacros/Plugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import SwiftSyntaxMacros
@main
struct Plugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [
WriterMacro.self
WriterMacro.self,
MarkerMacro.self,
]
}
17 changes: 17 additions & 0 deletions Sources/StructTransactionMacros/WriterMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,16 @@ extension WriterMacro: ExtensionMacro {
return ""
}

let functions = declaration
.memberBlock
.members
.compactMap {
$0.as(MemberBlockItemSyntax.self)?.decl.as(FunctionDeclSyntax.self)
}
.filter {
$0.attributes.contains { $0.trimmed.description == "@Exporting" }
}

let c = PropertyCollector(viewMode: .all)
c.onError = { node, error in
context.addDiagnostics(from: error, node: node)
Expand Down Expand Up @@ -124,7 +134,13 @@ extension WriterMacro: ExtensionMacro {
self.pointer = pointer
}

// MARK: - Properties

\(raw: decls.joined(separator: "\n\n"))

// MARK: - Functions

\(raw: functions.map(\.description).joined(separator: "\n\n"))
}
""" as DeclSyntax

Expand Down Expand Up @@ -162,6 +178,7 @@ extension WriterMacro: ExtensionMacro {
}

\(modifyingStructDecl)

""" as CodeBlockItemListSyntax)

return modifyingDecl
Expand Down
88 changes: 88 additions & 0 deletions Tests/StructTransactionMacroTests/WriterMacroTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,94 @@ final class WriterMacroTests: XCTestCase {
}
}

func test_copying_functions() {

assertMacro {
"""
@Detecting
struct MyState {
func hello() {
}

@Exporting
func hello2() {
}
}
"""
} expansion: {
"""
struct MyState {
func hello() {
}

@Exporting
func hello2() {
}
}

extension MyState: DetectingType {

// MARK: - Accessing
typealias AccessingTarget = Self

@discardableResult
public static func modify(source: inout Self, modifier: (inout Accessing) throws -> Void) rethrows -> AccessingResult {

try withUnsafeMutablePointer(to: &source) { pointer in
var modifying = Accessing(pointer: pointer)
try modifier(&modifying)
return AccessingResult(
readIdentifiers: modifying.$_readIdentifiers,
modifiedIdentifiers: modifying.$_modifiedIdentifiers
)
}
}

@discardableResult
public static func read(source: consuming Self, reader: (inout Accessing) throws -> Void) rethrows -> AccessingResult {

// TODO: check copying costs
var tmp = source

return try withUnsafeMutablePointer(to: &tmp) { pointer in
var modifying = Accessing(pointer: pointer)
try reader(&modifying)
return AccessingResult(
readIdentifiers: modifying.$_readIdentifiers,
modifiedIdentifiers: modifying.$_modifiedIdentifiers
)
}
}

public struct Accessing /* want to be ~Copyable */ {

public private (set) var $_readIdentifiers: Set<String> = .init()
public private (set) var $_modifiedIdentifiers: Set<String> = .init()

private let pointer: UnsafeMutablePointer<AccessingTarget>

init(pointer: UnsafeMutablePointer<AccessingTarget>) {
self.pointer = pointer
}

// MARK: - Properties



// MARK: - Functions



@Exporting
func hello2() {
}
}

}
"""
}
}

func test_() {

assertMacro {
Expand Down
5 changes: 5 additions & 0 deletions Tests/StructTransactionTests/MyState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,9 @@ struct MyState {
var name: String = ""
}

@Exporting
mutating func updateName() {
self.name = "Hiroshi"
}

}