From 71d5c1f2afc6a2c809efb42eba731948d2ac8747 Mon Sep 17 00:00:00 2001 From: Sean Date: Fri, 27 Sep 2024 17:02:22 -0400 Subject: [PATCH 1/5] Modified `Gen` to be `Sendable`. Requires its `Value` to also be `Sendable` --- Package.swift | 8 +- Sources/Gen/Gen.swift | 144 +++++++++++++++++++++------------- Sources/Gen/Zip.swift | 22 ++++++ Tests/GenTests/GenTests.swift | 4 +- 4 files changed, 121 insertions(+), 57 deletions(-) diff --git a/Package.swift b/Package.swift index 55aa546..c727a75 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.0 +// swift-tools-version:5.9 import Foundation import PackageDescription @@ -8,7 +8,11 @@ let package = Package( .library(name: "Gen", targets: ["Gen"]) ], targets: [ - .target(name: "Gen", dependencies: []), + .target( + name: "Gen", + dependencies: [], + swiftSettings: [.enableExperimentalFeature("StrictConcurrency")] + ), .testTarget(name: "GenTests", dependencies: ["Gen"]), ] ) diff --git a/Sources/Gen/Gen.swift b/Sources/Gen/Gen.swift index 04c072e..b46fd20 100644 --- a/Sources/Gen/Gen.swift +++ b/Sources/Gen/Gen.swift @@ -1,10 +1,10 @@ /// A composable, transformable context for generating random values. -public struct Gen { +public struct Gen: Sendable { @usableFromInline - internal var _run: (inout AnyRandomNumberGenerator) -> Value + internal var _run: @Sendable (inout AnyRandomNumberGenerator) -> Value @inlinable - public init(run: @escaping (inout AnyRandomNumberGenerator) -> Value) { + public init(run: @escaping @Sendable (inout AnyRandomNumberGenerator) -> Value) { self._run = run } @@ -13,6 +13,7 @@ public struct Gen { /// - Parameter rng: A random number generator. /// - Returns: A random value. @inlinable + @Sendable public func run(using rng: inout G) -> Value { if var arng = rng as? AnyRandomNumberGenerator { defer { rng = arng as! G } @@ -27,6 +28,7 @@ public struct Gen { /// /// - Returns: A random value. @inlinable + @Sendable public func run() -> Value { var rng = SystemRandomNumberGenerator() return self.run(using: &rng) @@ -39,6 +41,7 @@ extension Gen { /// - Parameter value: A constant value. /// - Returns: A generator of a constant value. @inlinable + @Sendable public static func always(_ value: Value) -> Gen { return Gen { _ in value } } @@ -48,31 +51,24 @@ extension Gen { /// - Parameter transform: A function that transforms `Value`s into `NewValue`s. /// - Returns: A generator of `NewValue`s. @inlinable - public func map(_ transform: @escaping (Value) -> NewValue) -> Gen { + @Sendable + public func map( + _ transform: @escaping @Sendable (Value) -> NewValue + ) -> Gen { return Gen { rng in transform(self._run(&rng)) } } } -/// Combines two generators into a single one. -/// -/// - Parameters: -/// - a: A generator of `A`s. -/// - b: A generator of `B`s. -/// - Returns: A generator of `(A, B)` pairs. -@inlinable -public func zip(_ a: Gen, _ b: Gen) -> Gen<(A, B)> { - return Gen<(A, B)> { rng in - (a._run(&rng), b._run(&rng)) - } -} - extension Gen { /// Transforms a generator of `Value`s into a generator of `NewValue`s by transforming a value into a generator of `NewValue`s. /// /// - Parameter transform: A function that transforms `Value`s into a generator of `NewValue`s. /// - Returns: A generator of `NewValue`s. @inlinable - public func flatMap(_ transform: @escaping (Value) -> Gen) -> Gen { + @Sendable + public func flatMap( + _ transform: @escaping @Sendable (Value) -> Gen + ) -> Gen { return Gen { rng in transform(self._run(&rng))._run(&rng) } @@ -83,7 +79,10 @@ extension Gen { /// - Parameter transform: A closure that accepts an element of this sequence as its argument and returns an optional value. /// - Returns: A generator of the non-nil results of calling the given transformation with a value of the generator. @inlinable - public func compactMap(_ transform: @escaping (Value) -> NewValue?) -> Gen { + @Sendable + public func compactMap( + _ transform: @escaping @Sendable (Value) -> NewValue? + ) -> Gen { return Gen { rng in while true { if let value = transform(self._run(&rng)) { @@ -98,18 +97,21 @@ extension Gen { /// - Parameter predicate: A predicate. /// - Returns: A generator of values that match the predicate. @inlinable - public func filter(_ predicate: @escaping (Value) -> Bool) -> Gen { + @Sendable + public func filter(_ predicate: @escaping @Sendable (Value) -> Bool) -> Gen { return self.compactMap { predicate($0) ? $0 : nil } } /// Uses a weighted distribution to randomly select one of the generators in the list. @inlinable + @Sendable public static func frequency(_ distribution: (Int, Gen)...) -> Gen { return frequency(distribution) } /// Uses a weighted distribution to randomly select one of the generators in the list. @inlinable + @Sendable public static func frequency(_ distribution: [(Int, Gen)]) -> Gen { // TODO: Add `!distribution.isEmpty` precondition? let generators = distribution.flatMap { Array(repeating: $1, count: $0) } @@ -121,167 +123,182 @@ extension Gen { } } -extension Gen where Value: FixedWidthInteger { +extension Gen where Value: FixedWidthInteger & Sendable { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func int(in range: ClosedRange) -> Gen { return Gen { rng in Value.random(in: range, using: &rng) } } } -extension Gen where Value: BinaryFloatingPoint, Value.RawSignificand: FixedWidthInteger { +extension Gen where Value: BinaryFloatingPoint & Sendable, Value.RawSignificand: FixedWidthInteger { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func float(in range: ClosedRange) -> Gen { return Gen { rng in Value.random(in: range, using: &rng) } } } -extension Gen where Value == Int { +extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func int(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } } -extension Gen where Value == Int8 { +extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func int8(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } } -extension Gen where Value == Int16 { +extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func int16(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } } -extension Gen where Value == Int32 { +extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func int32(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } } -extension Gen where Value == Int64 { +extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func int64(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } } -extension Gen where Value == UInt { +extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func uint(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } } -extension Gen where Value == UInt8 { +extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func uint8(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } } -extension Gen where Value == UInt16 { +extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func uint16(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } } -extension Gen where Value == UInt32 { +extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func uint32(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } } -extension Gen where Value == UInt64 { +extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func uint64(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } } -extension Gen where Value == Double { +extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func double(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } } -extension Gen where Value == Float { +extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func float32(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } } #if !(os(Windows) || os(Android)) && (arch(i386) || arch(x86_64)) - extension Gen where Value == Float80 { + extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func float80(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -291,19 +308,20 @@ extension Gen where Value == Float { #if canImport(CoreGraphics) import CoreGraphics - extension Gen where Value == CGFloat { + extension Gen { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable + @Sendable public static func cgFloat(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } } #endif -extension Gen where Value == Bool { +extension Gen { /// A generator of random boolean values. public static let bool = Gen { rng in Bool.random(using: &rng) } } @@ -313,7 +331,9 @@ extension Gen { /// /// - Parameter collection: A collection. @inlinable - public static func element(of collection: C) -> Gen where C: Collection, Value == C.Element? { + @Sendable + public static func element(of collection: C) -> Gen + where C: Collection & Sendable, Value == C.Element? { return Gen { rng in collection.randomElement(using: &rng) } } @@ -321,12 +341,14 @@ extension Gen { /// /// - Parameter collection: A collection. @inlinable - public static func shuffled(_ collection: C) -> Gen where C: Collection, Value == [C.Element] { + @Sendable + public static func shuffled(_ collection: C) -> Gen + where C: Collection & Sendable, Value == [C.Element] { return Gen { rng in collection.shuffled(using: &rng) } } } -extension Gen where Value: Collection { +extension Gen where Value: Collection, Value.Element: Sendable { /// Produces a generator of random elements of this generator's collection. @inlinable public var element: Gen { @@ -340,7 +362,7 @@ extension Gen where Value: Collection { } } -extension Gen where Value: CaseIterable { +extension Gen where Value: CaseIterable, Value.AllCases: Sendable { /// Produces a generator of all case-iterable cases. @inlinable public static var allCases: Gen { @@ -354,6 +376,7 @@ extension Gen { /// - Parameter count: The size of the random collection. /// - Returns: A generator of collections. @inlinable + @Sendable public func collection(of count: Gen) -> Gen where C: RangeReplaceableCollection, C.Element == Value { return count.flatMap { count in @@ -369,12 +392,13 @@ extension Gen { } } } - + /// Produces a new generator of arrays of this generator's values. /// /// - Parameter count: The size of the random array. /// - Returns: A generator of arrays. @inlinable + @Sendable public func array(of count: Gen) -> Gen<[Value]> { return count.flatMap { count in guard count > 0 else { return .always([]) } @@ -388,12 +412,13 @@ extension Gen { } } } - + /// Produces a new generator of dictionaries of this generator's pairs. /// /// - Parameter count: The size of the random dictionary. /// - Returns: A generator of dictionaries. @inlinable + @Sendable public func dictionary(ofAtMost count: Gen) -> Gen<[K: V]> where Value == (K, V) { return count.flatMap { count in guard count > 0 else { return .always([:]) } @@ -408,12 +433,13 @@ extension Gen { } } } - + /// Produces a new generator of sets of this generator's values. /// /// - Parameter count: The size of the random set. /// - Returns: A generator of sets. @inlinable + @Sendable public func set(ofAtMost count: Gen) -> Gen where S: SetAlgebra, S.Element == Value { return count.flatMap { count in guard count > 0 else { return .always(S()) } @@ -426,7 +452,9 @@ extension Gen { } } } +} +extension Gen { /// Produces a new generator of optional values. /// /// - Returns: A generator of optional values. @@ -434,7 +462,7 @@ extension Gen { public var optional: Gen { return Gen.frequency( (1, Gen.always(Value?.none)), - (3, self.map(Value?.some)) // TODO: Change to use `size` with resizable generators? + (3, self.map { Value?.some($0) }) // TODO: Change to use `size` with resizable generators? ) } @@ -442,10 +470,11 @@ extension Gen { /// /// - Returns: A generator of failable values. @inlinable + @Sendable public func asResult(withFailure gen: Gen) -> Gen> { return Gen>.frequency( - (1, gen.map(Result.failure)), - (3, self.map(Result.success)) // TODO: Change to use `size` with resizable generators? + (1, gen.map { Result.failure($0) }), + (3, self.map { Result.success($0) }) // TODO: Change to use `size` with resizable generators? ) } } @@ -456,6 +485,7 @@ extension Gen where Value: Hashable { /// - Parameter count: The size of the random set. /// - Returns: A generator of sets. @inlinable + @Sendable public func set(ofAtMost count: Gen) -> Gen> { return count.flatMap { count in guard count > 0 else { return .always([]) } @@ -470,12 +500,13 @@ extension Gen where Value: Hashable { } } -extension Gen where Value == UnicodeScalar { +extension Gen { /// Returns a generator of random unicode scalars within the specified range. /// /// - Parameter range: The range in which to create a random unicode scalar. `range` must be finite. /// - Returns: A generator of random unicode scalars within the bounds of range. @inlinable + @Sendable public static func unicodeScalar(in range: ClosedRange) -> Gen { return Gen .int(in: range.lowerBound.value...range.upperBound.value) @@ -483,19 +514,20 @@ extension Gen where Value == UnicodeScalar { } } -extension Gen where Value == Character { +extension Gen { // FIXME: Make safe for characters with multiple scalars. /// Returns a generator of random characters within the specified range. /// /// - Parameter range: The range in which to create a random character. `range` must be finite. /// - Returns: A generator of random characters within the bounds of range. @inlinable + @Sendable public static func character(in range: ClosedRange) -> Gen { return Gen .unicodeScalar( in: range.lowerBound.unicodeScalars.first!...range.upperBound.unicodeScalars.last! ) - .map(Character.init) + .map { Character($0) } } /// A generator of random numeric digits. @@ -532,18 +564,24 @@ extension Gen where Value == Character { /// - Parameter count: The size of the random string. /// - Returns: A generator of strings. @inlinable + @Sendable public func string(of count: Gen) -> Gen { - return self.map(String.init).array(of: count).map { $0.joined() } + return self + .map { String($0) } + .array(of: count) + .map { $0.joined() } } } -extension Sequence { +extension Sequence where Self: Sendable, Element: Sendable { /// Transforms each value of an array of generators before rewrapping the array in an array generator. /// /// - Parameter transform: A transform function to apply to the value of each generator. /// - Returns: A generator of arrays. @inlinable - public func traverse(_ transform: @escaping (A) -> B) -> Gen<[B]> where Element == Gen { + public func traverse( + _ transform: @escaping @Sendable (A) -> B + ) -> Gen<[B]> where Element == Gen { return Gen<[B]> { rng in self.map { transform($0.run(using: &rng)) } } diff --git a/Sources/Gen/Zip.swift b/Sources/Gen/Zip.swift index 9fa3095..24cb696 100644 --- a/Sources/Gen/Zip.swift +++ b/Sources/Gen/Zip.swift @@ -1,4 +1,19 @@ +/// Combines two generators into a single one. +/// +/// - Parameters: +/// - a: A generator of `A`s. +/// - b: A generator of `B`s. +/// - Returns: A generator of `(A, B)` pairs. @inlinable +@Sendable +public func zip(_ a: Gen, _ b: Gen) -> Gen<(A, B)> { + return Gen<(A, B)> { rng in + (a._run(&rng), b._run(&rng)) + } +} + +@inlinable +@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -10,6 +25,7 @@ public func zip( } @inlinable +@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -22,6 +38,7 @@ public func zip( } @inlinable +@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -35,6 +52,7 @@ public func zip( } @inlinable +@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -49,6 +67,7 @@ public func zip( } @inlinable +@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -64,6 +83,7 @@ public func zip( } @inlinable +@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -80,6 +100,7 @@ public func zip( } @inlinable +@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -97,6 +118,7 @@ public func zip( } @inlinable +@Sendable public func zip( _ a: Gen, _ b: Gen, diff --git a/Tests/GenTests/GenTests.swift b/Tests/GenTests/GenTests.swift index 757aa38..c0fe07e 100644 --- a/Tests/GenTests/GenTests.swift +++ b/Tests/GenTests/GenTests.swift @@ -5,7 +5,7 @@ final class GenTests: XCTestCase { var xoshiro = Xoshiro(seed: 0) func testMap() { - let gen = Gen.bool.map(String.init) + let gen = Gen.bool.map { String($0) } XCTAssertEqual("false", gen.run(using: &xoshiro)) } @@ -101,7 +101,7 @@ final class GenTests: XCTestCase { } func testTraverse() { - let gen = [Gen.int(in: 1...100), Gen.int(in: 1_000...1_000_000)].traverse(String.init) + let gen = [Gen.int(in: 1...100), Gen.int(in: 1_000...1_000_000)].traverse { String($0) } XCTAssertEqual(["15", "18473"], gen.run(using: &xoshiro)) } From 1db3f1f6f40c1c4d805f17488a357f0f54ee3110 Mon Sep 17 00:00:00 2001 From: seanmrich Date: Fri, 27 Sep 2024 17:07:19 -0400 Subject: [PATCH 2/5] Update ci.yml --- .github/workflows/ci.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 75ef6bd..7d06236 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,17 +13,22 @@ jobs: name: MacOS runs-on: macOS-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Run tests run: make test-swift - name: Run tests run: make build-release-swift ubuntu: - name: Ubuntu + strategy: + matrix: + swift: + - '5.9' + name: Ubuntu (Swift ${{ matrix.swift }}) runs-on: ubuntu-latest + container: swift:${{ matrix.swift }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Run tests run: make test-linux - name: Build for release From c0bf72512b80fb3e9adf9a19b9e4fd92e780a65b Mon Sep 17 00:00:00 2001 From: seanmrich Date: Thu, 10 Oct 2024 12:46:19 -0400 Subject: [PATCH 3/5] Minimized use of Sendable to only what's necessary to make `Gen` Sendable --- Sources/Gen/Gen.swift | 44 ++++--------------------------------------- Sources/Gen/Zip.swift | 9 --------- 2 files changed, 4 insertions(+), 49 deletions(-) diff --git a/Sources/Gen/Gen.swift b/Sources/Gen/Gen.swift index b46fd20..57b44c8 100644 --- a/Sources/Gen/Gen.swift +++ b/Sources/Gen/Gen.swift @@ -13,7 +13,6 @@ public struct Gen: Sendable { /// - Parameter rng: A random number generator. /// - Returns: A random value. @inlinable - @Sendable public func run(using rng: inout G) -> Value { if var arng = rng as? AnyRandomNumberGenerator { defer { rng = arng as! G } @@ -28,7 +27,6 @@ public struct Gen: Sendable { /// /// - Returns: A random value. @inlinable - @Sendable public func run() -> Value { var rng = SystemRandomNumberGenerator() return self.run(using: &rng) @@ -41,7 +39,6 @@ extension Gen { /// - Parameter value: A constant value. /// - Returns: A generator of a constant value. @inlinable - @Sendable public static func always(_ value: Value) -> Gen { return Gen { _ in value } } @@ -51,7 +48,6 @@ extension Gen { /// - Parameter transform: A function that transforms `Value`s into `NewValue`s. /// - Returns: A generator of `NewValue`s. @inlinable - @Sendable public func map( _ transform: @escaping @Sendable (Value) -> NewValue ) -> Gen { @@ -65,7 +61,6 @@ extension Gen { /// - Parameter transform: A function that transforms `Value`s into a generator of `NewValue`s. /// - Returns: A generator of `NewValue`s. @inlinable - @Sendable public func flatMap( _ transform: @escaping @Sendable (Value) -> Gen ) -> Gen { @@ -79,7 +74,6 @@ extension Gen { /// - Parameter transform: A closure that accepts an element of this sequence as its argument and returns an optional value. /// - Returns: A generator of the non-nil results of calling the given transformation with a value of the generator. @inlinable - @Sendable public func compactMap( _ transform: @escaping @Sendable (Value) -> NewValue? ) -> Gen { @@ -97,21 +91,18 @@ extension Gen { /// - Parameter predicate: A predicate. /// - Returns: A generator of values that match the predicate. @inlinable - @Sendable public func filter(_ predicate: @escaping @Sendable (Value) -> Bool) -> Gen { return self.compactMap { predicate($0) ? $0 : nil } } /// Uses a weighted distribution to randomly select one of the generators in the list. @inlinable - @Sendable public static func frequency(_ distribution: (Int, Gen)...) -> Gen { return frequency(distribution) } /// Uses a weighted distribution to randomly select one of the generators in the list. @inlinable - @Sendable public static func frequency(_ distribution: [(Int, Gen)]) -> Gen { // TODO: Add `!distribution.isEmpty` precondition? let generators = distribution.flatMap { Array(repeating: $1, count: $0) } @@ -123,25 +114,23 @@ extension Gen { } } -extension Gen where Value: FixedWidthInteger & Sendable { +extension Gen where Value: FixedWidthInteger { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func int(in range: ClosedRange) -> Gen { return Gen { rng in Value.random(in: range, using: &rng) } } } -extension Gen where Value: BinaryFloatingPoint & Sendable, Value.RawSignificand: FixedWidthInteger { +extension Gen where Value: BinaryFloatingPoint, Value.RawSignificand: FixedWidthInteger { /// Returns a generator of random values within the specified range. /// /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func float(in range: ClosedRange) -> Gen { return Gen { rng in Value.random(in: range, using: &rng) } } @@ -153,7 +142,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func int(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -165,7 +153,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func int8(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -177,7 +164,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func int16(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -189,7 +175,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func int32(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -201,7 +186,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func int64(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -213,7 +197,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func uint(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -225,7 +208,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func uint8(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -237,7 +219,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func uint16(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -249,7 +230,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func uint32(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -261,7 +241,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func uint64(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -273,7 +252,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func double(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -285,7 +263,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func float32(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -298,7 +275,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func float80(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -314,7 +290,6 @@ extension Gen { /// - Parameter range: The range in which to create a random value. `range` must be finite. /// - Returns: A generator of random values within the bounds of range. @inlinable - @Sendable public static func cgFloat(in range: ClosedRange) -> Gen { return Gen { rng in .random(in: range, using: &rng) } } @@ -331,7 +306,6 @@ extension Gen { /// /// - Parameter collection: A collection. @inlinable - @Sendable public static func element(of collection: C) -> Gen where C: Collection & Sendable, Value == C.Element? { return Gen { rng in collection.randomElement(using: &rng) } @@ -341,7 +315,6 @@ extension Gen { /// /// - Parameter collection: A collection. @inlinable - @Sendable public static func shuffled(_ collection: C) -> Gen where C: Collection & Sendable, Value == [C.Element] { return Gen { rng in collection.shuffled(using: &rng) } @@ -352,13 +325,13 @@ extension Gen where Value: Collection, Value.Element: Sendable { /// Produces a generator of random elements of this generator's collection. @inlinable public var element: Gen { - return self.flatMap(Gen.element) + self.flatMap { Gen.element(of: $0) } } /// Produces a generator of shuffled arrays of this generator's collection. @inlinable public var shuffled: Gen<[Value.Element]> { - return self.flatMap(Gen<[Value.Element]>.shuffled) + self.flatMap { Gen<[Value.Element]>.shuffled($0) } } } @@ -376,7 +349,6 @@ extension Gen { /// - Parameter count: The size of the random collection. /// - Returns: A generator of collections. @inlinable - @Sendable public func collection(of count: Gen) -> Gen where C: RangeReplaceableCollection, C.Element == Value { return count.flatMap { count in @@ -398,7 +370,6 @@ extension Gen { /// - Parameter count: The size of the random array. /// - Returns: A generator of arrays. @inlinable - @Sendable public func array(of count: Gen) -> Gen<[Value]> { return count.flatMap { count in guard count > 0 else { return .always([]) } @@ -418,7 +389,6 @@ extension Gen { /// - Parameter count: The size of the random dictionary. /// - Returns: A generator of dictionaries. @inlinable - @Sendable public func dictionary(ofAtMost count: Gen) -> Gen<[K: V]> where Value == (K, V) { return count.flatMap { count in guard count > 0 else { return .always([:]) } @@ -439,7 +409,6 @@ extension Gen { /// - Parameter count: The size of the random set. /// - Returns: A generator of sets. @inlinable - @Sendable public func set(ofAtMost count: Gen) -> Gen where S: SetAlgebra, S.Element == Value { return count.flatMap { count in guard count > 0 else { return .always(S()) } @@ -470,7 +439,6 @@ extension Gen { /// /// - Returns: A generator of failable values. @inlinable - @Sendable public func asResult(withFailure gen: Gen) -> Gen> { return Gen>.frequency( (1, gen.map { Result.failure($0) }), @@ -485,7 +453,6 @@ extension Gen where Value: Hashable { /// - Parameter count: The size of the random set. /// - Returns: A generator of sets. @inlinable - @Sendable public func set(ofAtMost count: Gen) -> Gen> { return count.flatMap { count in guard count > 0 else { return .always([]) } @@ -506,7 +473,6 @@ extension Gen { /// - Parameter range: The range in which to create a random unicode scalar. `range` must be finite. /// - Returns: A generator of random unicode scalars within the bounds of range. @inlinable - @Sendable public static func unicodeScalar(in range: ClosedRange) -> Gen { return Gen .int(in: range.lowerBound.value...range.upperBound.value) @@ -521,7 +487,6 @@ extension Gen { /// - Parameter range: The range in which to create a random character. `range` must be finite. /// - Returns: A generator of random characters within the bounds of range. @inlinable - @Sendable public static func character(in range: ClosedRange) -> Gen { return Gen .unicodeScalar( @@ -564,7 +529,6 @@ extension Gen { /// - Parameter count: The size of the random string. /// - Returns: A generator of strings. @inlinable - @Sendable public func string(of count: Gen) -> Gen { return self .map { String($0) } diff --git a/Sources/Gen/Zip.swift b/Sources/Gen/Zip.swift index 24cb696..3c6839c 100644 --- a/Sources/Gen/Zip.swift +++ b/Sources/Gen/Zip.swift @@ -5,7 +5,6 @@ /// - b: A generator of `B`s. /// - Returns: A generator of `(A, B)` pairs. @inlinable -@Sendable public func zip(_ a: Gen, _ b: Gen) -> Gen<(A, B)> { return Gen<(A, B)> { rng in (a._run(&rng), b._run(&rng)) @@ -13,7 +12,6 @@ public func zip(_ a: Gen, _ b: Gen) -> Gen<(A, B)> { } @inlinable -@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -25,7 +23,6 @@ public func zip( } @inlinable -@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -38,7 +35,6 @@ public func zip( } @inlinable -@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -52,7 +48,6 @@ public func zip( } @inlinable -@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -67,7 +62,6 @@ public func zip( } @inlinable -@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -83,7 +77,6 @@ public func zip( } @inlinable -@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -100,7 +93,6 @@ public func zip( } @inlinable -@Sendable public func zip( _ a: Gen, _ b: Gen, @@ -118,7 +110,6 @@ public func zip( } @inlinable -@Sendable public func zip( _ a: Gen, _ b: Gen, From 09e9641b2214b94f830e4c43de3a1900a9dd2318 Mon Sep 17 00:00:00 2001 From: seanmrich Date: Fri, 11 Oct 2024 06:19:12 -0400 Subject: [PATCH 4/5] Update ci.yml --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d06236..32ebf68 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,8 @@ jobs: container: swift:${{ matrix.swift }} steps: - uses: actions/checkout@v4 + - name: Install dependencies + run: apt-get update && apt-get install -y make - name: Run tests run: make test-linux - name: Build for release From afb216f138a00b9e04f1ed29df5186fb5a6716df Mon Sep 17 00:00:00 2001 From: seanmrich Date: Fri, 11 Oct 2024 06:31:25 -0400 Subject: [PATCH 5/5] Update ci.yml --- .github/workflows/ci.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 32ebf68..74d27e2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,9 +29,7 @@ jobs: container: swift:${{ matrix.swift }} steps: - uses: actions/checkout@v4 - - name: Install dependencies - run: apt-get update && apt-get install -y make - name: Run tests - run: make test-linux - - name: Build for release - run: make build-release-linux + run: swift test --parallel + - name: Run tests (release) + run: swift test -c release --parallel