Skip to content

Commit

Permalink
vendorize more things
Browse files Browse the repository at this point in the history
  • Loading branch information
ndurell committed Nov 5, 2024
1 parent 05f7715 commit 1a33d23
Show file tree
Hide file tree
Showing 59 changed files with 4,204 additions and 46 deletions.
2 changes: 1 addition & 1 deletion .swiftformat
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

# format options

--exclude Sources/KlaviyoSwift/Vendor,Tests/KlaviyoSwiftTests/Vendor,Tests/KlaviyoSwiftTests/__Snapshots__
--exclude Sources/ConcurrencyExtras,Sources/IssueReporting,Sources/Perception,Sources/IdentifiedCollections,Sources/InternalCollectionsUtilities,Sources/OrderedCollections,Sources/ComposableArchitecture,Sources/KlaviyoSwift/Vendor,Tests/KlaviyoSwiftTests/Vendor,Tests/KlaviyoSwiftTests/__Snapshots__
--closingparen same-line
--commas inline
--comments indent
Expand Down
3 changes: 3 additions & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ excluded: # paths to ignore during linting. Takes precedence over `included`.
- Sources/IdentifiedCollections
- Sources/InternalCollectionsUtilities
- Sources/OrderedCollections
- Sources/Perception
- Sources/IssueReporting
- Sources/ConcurrencyExtras
analyzer_rules: # Rules run by `swiftlint analyze` (experimental)
- explicit_self

Expand Down
11 changes: 1 addition & 10 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"originHash" : "1b089c9aad26faecca73e784aae45fdd744bc3b1d0ab628e73c9a3f9f3e19496",
"originHash" : "8c8cc3892336bc65f365db717e661c18dd83e787da8adb8ec838990b62c6de14",
"pins" : [
{
"identity" : "combine-schedulers",
Expand Down Expand Up @@ -37,15 +37,6 @@
"version" : "1.3.3"
}
},
{
"identity" : "swift-perception",
"kind" : "remoteSourceControl",
"location" : "https://github.com/pointfreeco/swift-perception",
"state" : {
"revision" : "bc67aa8e461351c97282c2419153757a446ae1c9",
"version" : "1.3.5"
}
},
{
"identity" : "swift-snapshot-testing",
"kind" : "remoteSourceControl",
Expand Down
29 changes: 18 additions & 11 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@ let package = Package(
.package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.10.0"),
.package(url: "https://github.com/pointfreeco/swift-custom-dump", from: "1.3.2"),
.package(url: "https://github.com/pointfreeco/swift-case-paths", from: "1.5.4"),
.package(url: "https://github.com/pointfreeco/swift-perception", from: "1.3.4"),
.package(url: "https://github.com/pointfreeco/combine-schedulers", from: "1.0.2"),
.package(url: "https://github.com/pointfreeco/xctest-dynamic-overlay", from: "1.3.0"),
.package(url: "https://github.com/pointfreeco/swift-concurrency-extras", from: "1.2.0"),
.package(url: "https://github.com/swiftlang/swift-syntax", "509.0.0"..<"601.0.0-prerelease")
.package(url: "https://github.com/pointfreeco/combine-schedulers", from: "1.0.2")
],
targets: [
.target(
Expand Down Expand Up @@ -59,7 +55,8 @@ let package = Package(
.product(name: "CasePaths", package: "swift-case-paths"),
.product(name: "CombineSchedulers", package: "combine-schedulers"),
"KlaviyoCore",
"ComposableArchitecture"
"ComposableArchitecture",
"KIssueReporting"
],
exclude: [
"__Snapshots__"
Expand All @@ -84,12 +81,11 @@ let package = Package(
.target(
name: "ComposableArchitecture",
dependencies: [
.product(name: "Perception", package: "swift-perception"),
.product(name: "ConcurrencyExtras", package: "swift-concurrency-extras"),
.product(name: "IssueReporting", package: "xctest-dynamic-overlay"),
.product(name: "CasePaths", package: "swift-case-paths"),
.product(name: "CustomDump", package: "swift-custom-dump"),
"IdentifiedCollections"
"IdentifiedCollections",
"KConcurrencyExtras",
"KPerception"
],
path: "Sources/ComposableArchitecture"),
.target(
Expand All @@ -107,6 +103,17 @@ let package = Package(
.target(
name: "AnyCodable",
dependencies: [],
path: "Sources/AnyCodable")
path: "Sources/AnyCodable"),
.target(
name: "KConcurrencyExtras",
dependencies: [],
path: "Sources/ConcurrencyExtras"),
.target(name: "KPerception",
dependencies: ["KIssueReporting"],
path: "Sources/Perception"),
.target(
name: "KIssueReporting",
dependencies: [],
path: "Sources/IssueReporting")

])
28 changes: 18 additions & 10 deletions [email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,7 @@ let package = Package(
.package(url: "https://github.com/pointfreeco/swift-snapshot-testing", from: "1.10.0"),
.package(url: "https://github.com/pointfreeco/swift-custom-dump", from: "1.3.2"),
.package(url: "https://github.com/pointfreeco/swift-case-paths", from: "1.5.4"),
.package(url: "https://github.com/pointfreeco/swift-perception", from: "1.3.4"),
.package(url: "https://github.com/pointfreeco/combine-schedulers", from: "1.0.2"),
.package(url: "https://github.com/pointfreeco/xctest-dynamic-overlay", from: "1.3.0"),
.package(url: "https://github.com/pointfreeco/swift-concurrency-extras", from: "1.2.0")
.package(url: "https://github.com/pointfreeco/combine-schedulers", from: "1.0.2")
],
targets: [
.target(
Expand Down Expand Up @@ -57,7 +54,8 @@ let package = Package(
.product(name: "CasePaths", package: "swift-case-paths"),
.product(name: "CombineSchedulers", package: "combine-schedulers"),
"KlaviyoCore",
"ComposableArchitecture"
"ComposableArchitecture",
"KIssueReporting"
],
exclude: [
"__Snapshots__"
Expand All @@ -82,12 +80,11 @@ let package = Package(
.target(
name: "ComposableArchitecture",
dependencies: [
.product(name: "Perception", package: "swift-perception"),
.product(name: "ConcurrencyExtras", package: "swift-concurrency-extras"),
.product(name: "IssueReporting", package: "xctest-dynamic-overlay"),
.product(name: "CasePaths", package: "swift-case-paths"),
.product(name: "CustomDump", package: "swift-custom-dump"),
"IdentifiedCollections"
"IdentifiedCollections",
"KConcurrencyExtras",
"KPerception"
],
path: "Sources/ComposableArchitecture"),
.target(
Expand All @@ -105,6 +102,17 @@ let package = Package(
.target(
name: "AnyCodable",
dependencies: [],
path: "Sources/AnyCodable")
path: "Sources/AnyCodable"),
.target(
name: "KConcurrencyExtras",
dependencies: [],
path: "Sources/ConcurrencyExtras"),
.target(name: "KPerception",
dependencies: ["KIssueReporting"],
path: "Sources/Perception"),
.target(
name: "KIssueReporting",
dependencies: [],
path: "Sources/IssueReporting")
],
swiftLanguageModes: [.v6])
4 changes: 2 additions & 2 deletions Sources/ComposableArchitecture/Effect.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@preconcurrency import Combine
import ConcurrencyExtras
import KConcurrencyExtras
import CustomDump
import Foundation
import IssueReporting
Expand All @@ -15,7 +15,7 @@ public struct Effect<Action>: Sendable {

@usableFromInline
let operation: Operation

@usableFromInline
init(operation: Operation) {
self.operation = operation
Expand Down
2 changes: 1 addition & 1 deletion Sources/ComposableArchitecture/Effects/Cancellation.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
@preconcurrency import Combine
import ConcurrencyExtras
import KConcurrencyExtras
import Foundation

extension Effect {
Expand Down
2 changes: 1 addition & 1 deletion Sources/ComposableArchitecture/Internal/Create.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
// THE SOFTWARE.

@preconcurrency import Combine
import ConcurrencyExtras
import KConcurrencyExtras
import Darwin

final class DemandBuffer<S: Subscriber>: @unchecked Sendable {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation
import IdentifiedCollections
import Perception
import KPerception

/// A type that emits notifications to observers when underlying data changes.
///
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import CasePaths
import Perception
import KPerception
import SwiftUI
import XCTestDynamicOverlay

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Perception
import KPerception

/// Provides storage for tracking and access to data changes.
struct ObservationStateRegistrar: Sendable {
Expand Down
4 changes: 2 additions & 2 deletions Sources/ComposableArchitecture/RootStore.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Combine
import ConcurrencyExtras
import KConcurrencyExtras
import CustomDump
import Foundation
import Perception
import KPerception
import XCTestDynamicOverlay

@_spi(Internals)
Expand Down
2 changes: 1 addition & 1 deletion Sources/ComposableArchitecture/Store.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import CasePaths
import Combine
import Foundation
import Perception
import KPerception
import SwiftUI

/// A store represents the runtime that powers the application. It is the object that you will pass
Expand Down
113 changes: 113 additions & 0 deletions Sources/ConcurrencyExtras/ActorIsolated.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/// A generic wrapper for isolating a mutable value to an actor.
///
/// This type is most useful when writing tests for when you want to inspect what happens inside an
/// async operation.
///
/// For example, suppose you have a feature such that when a button is tapped you track some
/// analytics:
///
/// ```swift
/// struct AnalyticsClient {
/// var track: (String) async -> Void
/// }
///
/// class FeatureModel: ObservableObject {
/// let analytics: AnalyticsClient
/// // ...
/// func buttonTapped() {
/// // ...
/// await self.analytics.track("Button tapped")
/// }
/// }
/// ```
///
/// Then, in tests we can construct an analytics client that appends events to a mutable array
/// rather than actually sending events to an analytics server. However, in order to do this in a
/// safe way we should use an actor, and `ActorIsolated` makes this easy:
///
/// ```swift
/// func testAnalytics() async {
/// let events = ActorIsolated<[String]>([])
/// let analytics = AnalyticsClient(
/// track: { event in await events.withValue { $0.append(event) } }
/// )
/// let model = FeatureModel(analytics: analytics)
/// model.buttonTapped()
/// await events.withValue {
/// XCTAssertEqual($0, ["Button tapped"])
/// }
/// }
/// ```
///
/// To synchronously isolate a value, see ``LockIsolated``.
@available(*, deprecated, message: "Use 'LockIsolated' instead.")
public final actor ActorIsolated<Value> {
/// The actor-isolated value.
public var value: Value

/// Initializes actor-isolated state around a value.
///
/// - Parameter value: A value to isolate in an actor.
public init(_ value: @autoclosure @Sendable () throws -> Value) rethrows {
self.value = try value()
}

/// Perform an operation with isolated access to the underlying value.
///
/// Useful for modifying a value in a single transaction.
///
/// ```swift
/// // Isolate an integer for concurrent read/write access:
/// let count = ActorIsolated(0)
///
/// func increment() async {
/// // Safely increment it:
/// await self.count.withValue { $0 += 1 }
/// }
/// ```
///
/// > Tip: Because XCTest assertions don't play nicely with Swift concurrency, `withValue` also
/// > provides a handy interface to peek at an actor-isolated value and assert against it:
/// >
/// > ```swift
/// > let didOpenSettings = ActorIsolated(false)
/// > let model = withDependencies {
/// > $0.openSettings = { await didOpenSettings.setValue(true) }
/// > } operation: {
/// > FeatureModel()
/// > }
/// > await model.settingsButtonTapped()
/// > await didOpenSettings.withValue { XCTAssertTrue($0) }
/// > ```
///
/// - Parameter operation: An operation to be performed on the actor with the underlying value.
/// - Returns: The result of the operation.
public func withValue<T>(
_ operation: @Sendable (inout Value) throws -> T
) rethrows -> T {
var value = self.value
defer { self.value = value }
return try operation(&value)
}

/// Overwrite the isolated value with a new value.
///
/// ```swift
/// // Isolate an integer for concurrent read/write access:
/// let count = ActorIsolated(0)
///
/// func reset() async {
/// // Reset it:
/// await self.count.setValue(0)
/// }
/// ```
///
/// > Tip: Use ``withValue(_:)`` instead of `setValue` if the value being set is derived from the
/// > current value. This isolates the entire transaction and avoids data races between reading
/// > and writing the value.
///
/// - Parameter newValue: The value to replace the current isolated value with.
public func setValue(_ newValue: @autoclosure @Sendable () throws -> Value) rethrows {
self.value = try newValue()
}
}
42 changes: 42 additions & 0 deletions Sources/ConcurrencyExtras/AnyHashableSendable.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/// A type-erased hashable, sendable value.
///
/// A sendable version of `AnyHashable` that is useful in working around the limitation that an
/// existential `any Hashable` does not conform to `Hashable`.
public struct AnyHashableSendable: Hashable, Sendable {
public let base: any Hashable & Sendable

/// Creates a type-erased hashable, sendable value that wraps the given instance.
public init(_ base: some Hashable & Sendable) {
if let base = base as? AnyHashableSendable {
self = base
} else {
self.base = base
}
}

public static func == (lhs: Self, rhs: Self) -> Bool {
AnyHashable(lhs.base) == AnyHashable(rhs.base)
}

public func hash(into hasher: inout Hasher) {
hasher.combine(base)
}
}

extension AnyHashableSendable: CustomDebugStringConvertible {
public var debugDescription: String {
"AnyHashableSendable(" + String(reflecting: base) + ")"
}
}

extension AnyHashableSendable: CustomReflectable {
public var customMirror: Mirror {
Mirror(self, children: ["value": base])
}
}

extension AnyHashableSendable: CustomStringConvertible {
public var description: String {
String(describing: base)
}
}
Loading

0 comments on commit 1a33d23

Please sign in to comment.