Skip to content

Commit

Permalink
add functions
Browse files Browse the repository at this point in the history
  • Loading branch information
crane-hiromu committed Oct 29, 2022
1 parent b394df8 commit 61ca706
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
28 changes: 28 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// swift-tools-version: 5.6
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "CombineAsyncable",
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
.library(
name: "CombineAsyncable",
targets: ["CombineAsyncable"]),
],
dependencies: [
// Dependencies declare other packages that this package depends on.
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
// Targets can depend on other targets in this package, and on products in packages this package depends on.
.target(
name: "CombineAsyncable",
dependencies: []),
.testTarget(
name: "CombineAsyncableTests",
dependencies: ["CombineAsyncable"]),
]
)
65 changes: 65 additions & 0 deletions Sources/CombineAsyncable/Future+Task.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//
// Future+Task.swift
//
//
// Created by h.tsuruta on 2022/10/06.
//

#if compiler(>=5.5) && canImport(_Concurrency)
import Combine

// MARK: - Future Extension (Never)
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
extension Future where Failure == Never {

/// Example
///
/// func exec() -> Future<(), Never> {
/// Future {
/// await callAsyncFunction()
/// }
/// }
///
convenience init(
priority: TaskPriority? = nil,
operation: @escaping () async -> Output
) {
self.init { promise in
Task(priority: priority) {
let result = await operation()
promise(.success(result))
}
}
}
}

// MARK: - Future Extension (Error)
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
extension Future where Failure == Error {

/// Example
///
/// func exec() -> Future<(), Error> {
/// Future {
/// try await callAsyncThrowsFunction()
/// }
/// }
///
convenience init(
priority: TaskPriority? = nil,
operation: @escaping () async throws -> Output
) {
self.init { promise in
Task(priority: priority) {
do {
let result = try await operation()
promise(.success(result))
} catch {
promise(.failure(error))
}
}
}
}
}

#endif
129 changes: 129 additions & 0 deletions Sources/CombineAsyncable/Publisher+Task.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//
// Publisher+Task.swift
//
//
// Created by h.tsuruta on 2022/10/06.
//

#if compiler(>=5.5) && canImport(_Concurrency)
import Combine

// MARK: - Publisher Extension (Never)
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
public extension Publisher where Self.Failure == Never {

/// Example
///
/// Just<Int>(99)
/// .sink { number in
/// // do some task
/// }
/// .store(in: &cancellable)
///
func sink(
receiveValue: @escaping ((Self.Output) async -> Void)
) -> AnyCancellable {
self.sink { value in
Task {
await receiveValue(value)
}
}
}
}

// MARK: - Publisher Extension (Error)
@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
public extension Publisher where Self.Failure == Error {

/// Example
///
/// Just<Int>(99)
/// .setFailureType(to: Error.self)
/// .sinkWithThrows(receiveCompletion: { result in
/// // do some resut handling task
/// }, receiveValue: { value in
/// // do some value handling task
/// })
/// .store(in: &cancellable)
///
func sinkWithThrows(
receiveCompletion: @escaping ((Subscribers.Completion<Self.Failure>) async throws -> Void),
receiveValue: @escaping ((Self.Output) async throws -> Void)
) -> AnyCancellable {
self.sink(
receiveCompletion: { result in
Task {
try await receiveCompletion(result)
}
},
receiveValue: { value in
Task {
try await receiveValue(value)
}
}
)
}
}

@available(macOS 12.0, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
public extension Publisher {

/// Example
///
/// Just<Int>(99)
/// .asyncMap { number in
/// // do some task
/// }
/// .sink { number in
/// // do some handling
/// }
/// .store(in: &cancellable)
///
func asyncMap<V>(
_ asyncFunction: @escaping (Output) async -> V
) -> Publishers.FlatMap<Future<V, Never>, Self> {

flatMap { value in
Future { promise in
Task {
promise(.success(await asyncFunction(value)))
}
}
}
}

/// Example
///
/// URL(string: "https....")
/// .publisher
/// .compactMap { $0 }
/// .asyncMapWithThrows {
/// try await URLSession.shared.data(from: $0)
/// }
/// .sink(receiveCompletion: { result in
/// // do some result handling task
/// }, receiveValue: { value in
/// // do some value handling task
/// })
/// .store(in: &cancellable)
///
func asyncMapWithThrows<V>(
_ transform: @escaping (Output) async throws -> V
) -> Publishers.FlatMap<Future<V, Error>, Publishers.SetFailureType<Self, Error>> {

flatMap { value in
Future { promise in
Task {
do {
let output = try await transform(value)
promise(.success(output))
} catch {
promise(.failure(error))
}
}
}
}
}
}

#endif
11 changes: 11 additions & 0 deletions Tests/CombineAsyncableTests/CombineAsyncableTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import XCTest
@testable import CombineAsyncable

final class CombineAsyncableTests: XCTestCase {
func testExample() throws {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct
// results.
XCTAssertEqual(CombineAsyncable().text, "Hello, World!")
}
}

0 comments on commit 61ca706

Please sign in to comment.