Skip to content

swift-developer-tools/swift-reasync

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

swift-reasync

Compile-time generation of synchronous overloads from asynchronous function declarations.

Overview

Libraries that provide both synchronous and asynchronous variants of the same function must maintain two nearly-identical declarations that typically differ only in their use of async/await keywords. swift-reasync eliminates this duplication with a macro that generates a synchronous peer overload at compile time.

The transformation is purely syntactic, removing the async and await keywords wherever they appear, along with the related concurrency annotations that are either invalid on synchronous forms or that the peer's synchronous body can no longer support. All other syntax is preserved.

The generated function must be valid in a synchronous context without further modification. If the function body contains operations that are inherently asynchronous, such as calls to actor-isolated methods or async-only APIs, the generated synchronous overload will not compile.

@Reasync
func double(
    _ value: Int
) async throws -> Int
{
    return value * 2
}

// Generated by @Reasync:
//
// func double(
//     _ value: Int
// ) throws -> Int
// {
//     return value * 2
// }

await expressions, async let bindings, and for await loops in the function body are transformed to their synchronous equivalents.

@Reasync
func doubleThenAdd(
    _ a: Int,
    _ b: Int
) async -> Int
{
    async let x : Int   = double(a)
    async let y : Int   = double(b)
    
    return await x + y
}

// Generated by @Reasync:
// 
// func doubleThenAdd(
//     _ a: Int,
//     _ b: Int
// ) -> Int
// {
//     let x : Int   = double(a)
//     let y : Int   = double(b)
// 
//     return x + y
// }

Strict Concurrency

The macro's transformation removes async and await from the function declaration, but async functions in Swift 6 frequently carry additional annotations. The macro handles these as follows:

Annotation Rule Removal Scope
async, await Remove Everywhere
@isolated(any) Remove Closure parameter types (at any nesting depth)
nonisolated(nonsending) Remove Everywhere
@concurrent Remove Everywhere
@Sendable Remove Closure parameter types (at any nesting depth)
sending Preserve
Global actors Preserve
isolated parameters Preserve
Bare nonisolated Preserve

These rules are designed to produce a synchronous peer that is type-correct under Swift 6 strict concurrency, without silently changing the meaning of annotations that are unrelated to concurrent execution.

Installation

Swift Package Manager

swift-reasync may be installed using Swift Package Manager.

// Import swift-reasync.
import Reasync

See Xcode documentation for instructions on how to add package dependencies.

Requirements

Platform Minimum Version
Swift 6.3
iOS 13.0
iPadOS 13.0
Mac Catalyst 13.0
macOS 10.15
tvOS 13.0
watchOS 6.0

License

swift-reasync is licensed under the Apache License, Version 2.0.

See LICENSE for the complete license terms.

About

Compile-time generation of synchronous overloads from asynchronous function declarations.

Resources

License

Code of conduct

Contributing

Stars

14 stars

Watchers

1 watching

Forks

Contributors

Languages