diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index b7e3e143..4fd9ea68 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -20,6 +20,10 @@ jobs: steps: - uses: actions/checkout@v4 + # default Xcode for macOS 14 image is v15.0.1 + - name: Select Xcode 15.3 + run: sudo xcode-select -s /Applications/Xcode_15.3.app + - name: Show Build SDK run: xcodebuild -showsdks diff --git a/Sources/Lindenmayer/Examples/Examples3D.swift b/Sources/Lindenmayer/Examples/Examples3D.swift index 5b2f2dee..9d9cb33e 100644 --- a/Sources/Lindenmayer/Examples/Examples3D.swift +++ b/Sources/Lindenmayer/Examples/Examples3D.swift @@ -218,7 +218,9 @@ public enum Examples3D: Sendable { /// ![A screenshot showing four rendered trees that correspond to the parameters as described in The Algorithmic Beauty of Plants for figure 2.6](rendered_2_6_trees.png) /// /// The example source for this L-system is [available on GitHub](https://github.com/heckj/Lindenmayer/blob/main/Sources/Lindenmayer/Examples3D.swift). - public static let monopodialTree = LSystem.create( + /// + + public static let monopodialTree: ParameterizedRandomContextualLSystem = LSystem.create( [Trunk(growthDistance: defines.trunklength, diameter: defines.trunkdiameter)], with: Xoshiro(seed: 42), using: defines @@ -349,7 +351,7 @@ public enum Examples3D: Sendable { /// ![A screenshot showing four rendered trees that correspond to the parameters as described in The Algorithmic Beauty of Plants for figure 2.7](rendered_2_7_trees.png) /// /// The example source for this L-system is [available on GitHub](https://github.com/heckj/Lindenmayer/blob/main/Sources/Lindenmayer/Examples3D.swift). - public static let sympodialTree = LSystem.create( + public static let sympodialTree: ParameterizedRandomContextualLSystem = LSystem.create( MainBranch(growthDistance: 10, diameter: 1), with: Xoshiro(seed: 0), using: figure2_7A @@ -415,19 +417,19 @@ public enum Examples3D: Sendable { } public static let randomBush = LSystem.create(Stem2(length: 1), with: Xoshiro(seed: 42)) - .rewriteWithRNG(directContext: Stem2.self) { stem, rng -> [Module] in + .rewriteWithRNG(directContext: Stem2.self) { stem, rng async -> [Module] in let upper: Float = 45.0 let lower: Float = 15.0 - if rng.p(0.5) { - return [ + if await rng.p(0.5) { + return await [ StaticStem2(length: 2), Modules.PitchDown(angle: Angle(degrees: Double(rng.randomFloat(in: lower ... upper)))), Stem2(length: stem.length), ] } else { - return [ + return await [ StaticStem2(length: 2), Modules.PitchUp(angle: Angle(degrees: Double(rng.randomFloat(in: lower ... upper)))), Stem2(length: stem.length), diff --git a/Sources/Lindenmayer/LSystem.swift b/Sources/Lindenmayer/LSystem.swift index fb5062f2..8f089ff8 100644 --- a/Sources/Lindenmayer/LSystem.swift +++ b/Sources/Lindenmayer/LSystem.swift @@ -55,7 +55,7 @@ public enum LSystem: Sendable { /// - Parameters: /// - axiom: An initial module that represents the initial state of the Lindenmayer system.. /// - prng: An optional psuedo-random number generator to use for randomness in rule productions. - public static func create(_ axiom: Module, with prng: RNGType?) -> RandomContextualLSystem { + public static func create(_ axiom: Module, with prng: RNGType?) -> RandomContextualLSystem { if let prng { return RandomContextualLSystem(axiom: [axiom], state: nil, newStateIndicators: nil, prng: RNGWrapper(prng)) } @@ -66,7 +66,7 @@ public enum LSystem: Sendable { /// - Parameters: /// - axiom: A sequence of modules that represents the initial state of the Lindenmayer system.. /// - prng: An optional psuedo-random number generator to use for for randomness in rule productions. - public static func create(_ axiom: [Module], with prng: RNGType?) -> RandomContextualLSystem { + public static func create(_ axiom: [Module], with prng: RNGType?) -> RandomContextualLSystem { if let prng { return RandomContextualLSystem(axiom: axiom, state: nil, newStateIndicators: nil, prng: RNGWrapper(prng)) } @@ -78,11 +78,11 @@ public enum LSystem: Sendable { /// - axiom: An initial module that represents the initial state of the Lindenmayer system. /// - prng: An optional psuedo-random number generator to use for for randomness in rule productions. /// - parameters: An instance of type you provide that the L-system provides to the rules you create for use as parameters. - public static func create(_ axiom: Module, with prng: RNGType?, using parameters: PType) -> ParameterizedRandomContextualLSystem { + public static func create(_ axiom: Module, with prng: RNGType?, using parameters: PType) -> ParameterizedRandomContextualLSystem { if let prng { - return ParameterizedRandomContextualLSystem(axiom: [axiom], state: nil, newStateIndicators: nil, parameters: ParametersWrapper(parameters), prng: RNGWrapper(prng), rules: []) + return ParameterizedRandomContextualLSystem(axiom: [axiom], state: nil, newStateIndicators: nil, parameters: parameters, prng: RNGWrapper(prng), rules: []) } - return ParameterizedRandomContextualLSystem(axiom: [axiom], state: nil, newStateIndicators: nil, parameters: ParametersWrapper(parameters), prng: RNGWrapper(Xoshiro(seed: 42) as! RNGType), rules: []) + return ParameterizedRandomContextualLSystem(axiom: [axiom], state: nil, newStateIndicators: nil, parameters: parameters, prng: RNGWrapper(Xoshiro(seed: 42) as! RNGType), rules: []) } /// Creates a new Lindenmayer system from an initial state, using the random number generator and parameter instance that you provide. @@ -90,10 +90,10 @@ public enum LSystem: Sendable { /// - axiom: A sequence of modules that represents the initial state of the Lindenmayer system.. /// - prng: An optional psuedo-random number generator to use for for randomness in rule productions. /// - parameters: An instance of type you provide that the L-system provides to the rules you create for use as parameters. - public static func create(_ axiom: [Module], with prng: RNGType?, using parameters: PType) -> ParameterizedRandomContextualLSystem { + public static func create(_ axiom: [Module], with prng: RNGType?, using parameters: PType) -> ParameterizedRandomContextualLSystem { if let prng { - return ParameterizedRandomContextualLSystem(axiom: axiom, state: nil, newStateIndicators: nil, parameters: ParametersWrapper(parameters), prng: RNGWrapper(prng), rules: []) + return ParameterizedRandomContextualLSystem(axiom: axiom, state: nil, newStateIndicators: nil, parameters: parameters, prng: RNGWrapper(prng), rules: []) } - return ParameterizedRandomContextualLSystem(axiom: axiom, state: nil, newStateIndicators: nil, parameters: ParametersWrapper(parameters), prng: RNGWrapper(Xoshiro(seed: 42) as! RNGType), rules: []) + return ParameterizedRandomContextualLSystem(axiom: axiom, state: nil, newStateIndicators: nil, parameters: parameters, prng: RNGWrapper(Xoshiro(seed: 42) as! RNGType), rules: []) } } diff --git a/Sources/Lindenmayer/LSystemTypes/ContextualLSystem.swift b/Sources/Lindenmayer/LSystemTypes/ContextualLSystem.swift index 0d7a530d..2c08446d 100644 --- a/Sources/Lindenmayer/LSystemTypes/ContextualLSystem.swift +++ b/Sources/Lindenmayer/LSystemTypes/ContextualLSystem.swift @@ -132,8 +132,8 @@ public extension ContextualLSystem { /// - produces: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(_ direct: DC.Type, - where evalClosure: @escaping (DC) -> Bool, - produces produceClosure: @escaping (DC) -> [Module]) -> Self where DC: Module + where evalClosure: @Sendable @escaping (DC) -> Bool, + produces produceClosure: @Sendable @escaping (DC) -> [Module]) -> Self where DC: Module { let newRule = RewriteRuleDirect(direct: direct, where: evalClosure, produce: produceClosure) var newRuleSet: [Rule] = rules @@ -147,7 +147,7 @@ public extension ContextualLSystem { /// - produce: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(_ direct: DC.Type, - produces produceClosure: @escaping (DC) -> [Module]) -> Self where DC: Module + produces produceClosure: @Sendable @escaping (DC) -> [Module]) -> Self where DC: Module { let newRule = RewriteRuleDirect(direct: direct, where: nil, produce: produceClosure) var newRuleSet: [Rule] = rules @@ -162,8 +162,8 @@ public extension ContextualLSystem { /// - produces: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(leftContext: LC.Type, directContext: DC.Type, - where evalClosure: @escaping (LC, DC) -> Bool, - produces produceClosure: @escaping (LC, DC) -> [Module]) -> Self where LC: Module, DC: Module + where evalClosure: @Sendable @escaping (LC, DC) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC) -> [Module]) -> Self where LC: Module, DC: Module { let newRule = RewriteRuleLeftDirect(leftType: leftContext, directType: directContext, where: evalClosure, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -177,7 +177,7 @@ public extension ContextualLSystem { /// - produce: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(leftContext: LC.Type, directContext: DC.Type, - produces produceClosure: @escaping (LC, DC) -> [Module]) -> Self where LC: Module, DC: Module + produces produceClosure: @Sendable @escaping (LC, DC) -> [Module]) -> Self where LC: Module, DC: Module { let newRule = RewriteRuleLeftDirect(leftType: leftContext, directType: directContext, where: nil, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -192,8 +192,8 @@ public extension ContextualLSystem { /// - produces: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (DC, RC) -> Bool, - produces produceClosure: @escaping (DC, RC) -> [Module]) -> Self where DC: Module, RC: Module + where evalClosure: @Sendable @escaping (DC, RC) -> Bool, + produces produceClosure: @Sendable @escaping (DC, RC) -> [Module]) -> Self where DC: Module, RC: Module { let newRule = RewriteRuleDirectRight(directType: directContext, rightType: rightContext, where: evalClosure, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -207,7 +207,7 @@ public extension ContextualLSystem { /// - produce: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (DC, RC) -> [Module]) -> Self where DC: Module, RC: Module + produces produceClosure: @Sendable @escaping (DC, RC) -> [Module]) -> Self where DC: Module, RC: Module { let newRule = RewriteRuleDirectRight(directType: directContext, rightType: rightContext, where: nil, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -222,8 +222,8 @@ public extension ContextualLSystem { /// - produces: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (LC, DC, RC) -> Bool, - produces produceClosure: @escaping (LC, DC, RC) -> [Module]) -> Self where LC: Module, DC: Module, RC: Module + where evalClosure: @Sendable @escaping (LC, DC, RC) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC, RC) -> [Module]) -> Self where LC: Module, DC: Module, RC: Module { let newRule = RewriteRuleLeftDirectRight(leftType: leftContext, directType: directContext, rightType: rightContext, where: evalClosure, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -237,7 +237,7 @@ public extension ContextualLSystem { /// - produce: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (LC, DC, RC) -> [Module]) -> Self where LC: Module, DC: Module, RC: Module + produces produceClosure: @Sendable @escaping (LC, DC, RC) -> [Module]) -> Self where LC: Module, DC: Module, RC: Module { let newRule = RewriteRuleLeftDirectRight(leftType: leftContext, directType: directContext, rightType: rightContext, where: nil, produces: produceClosure) var newRuleSet: [Rule] = rules diff --git a/Sources/Lindenmayer/LSystemTypes/ParameterizedRandomContextualLSystem.swift b/Sources/Lindenmayer/LSystemTypes/ParameterizedRandomContextualLSystem.swift index 53b8061d..87f82a52 100644 --- a/Sources/Lindenmayer/LSystemTypes/ParameterizedRandomContextualLSystem.swift +++ b/Sources/Lindenmayer/LSystemTypes/ParameterizedRandomContextualLSystem.swift @@ -85,7 +85,7 @@ import Foundation /// /// - ``ParameterizedRandomContextualLSystem/reset()`` /// -public struct ParameterizedRandomContextualLSystem: LindenmayerSystem where PRNG: SeededRandomNumberGenerator { +public struct ParameterizedRandomContextualLSystem: LindenmayerSystem where PRNG: SeededRandomNumberGenerator, PType: Sendable { let axiom: [Module] /// The current state of the L-system, expressed as a sequence of elements that conform to Module. @@ -97,7 +97,7 @@ public struct ParameterizedRandomContextualLSystem: LindenmayerSyst public let newStateIndicators: [Bool] /// The parameters to provide to rules for evaluation and production. - let parameters: ParametersWrapper + let parameters: PType let initialParameters: PType let prng: RNGWrapper @@ -116,13 +116,13 @@ public struct ParameterizedRandomContextualLSystem: LindenmayerSyst public init(axiom: [Module], state: [Module]?, newStateIndicators: [Bool]?, - parameters: ParametersWrapper, + parameters: PType, prng: RNGWrapper, rules: [Rule] = []) { // Using [axiom] instead of [] ensures that we always have a state // environment that can be evolved based on the rules available. - initialParameters = parameters.unwrap() + initialParameters = parameters self.axiom = axiom if let state { self.state = state @@ -153,9 +153,8 @@ public struct ParameterizedRandomContextualLSystem: LindenmayerSyst ParameterizedRandomContextualLSystem(axiom: axiom, state: state, newStateIndicators: newItemIndicators, parameters: parameters, prng: prng, rules: rules) } - public func reset() -> Self { - prng.resetRNG(seed: prng.seed) - parameters.update(initialParameters) + public func reset() async -> Self { + await prng.resetRNG(seed: prng.seed) return ParameterizedRandomContextualLSystem(axiom: axiom, state: nil, newStateIndicators: nil, parameters: parameters, prng: prng, rules: rules) } @@ -163,8 +162,8 @@ public struct ParameterizedRandomContextualLSystem: LindenmayerSyst /// - Parameter seed: The seed value to set within the pseudo-random generator. /// - Returns: The L-system with the seed value updated. @discardableResult - public func setSeed(seed: UInt64) -> Self { - prng.resetRNG(seed: seed) + public func setSeed(seed: UInt64) async -> Self { + await prng.resetRNG(seed: seed) return self } @@ -173,8 +172,7 @@ public struct ParameterizedRandomContextualLSystem: LindenmayerSyst /// - Returns: The L-system with the parameters value updated. @discardableResult public func setParameters(params: PType) -> Self { - parameters.update(params) - return self + Self(axiom: axiom, state: state, newStateIndicators: newStateIndicators, parameters: params, prng: prng, rules: rules) } /// Sets the seed for the pseudo-random number generator and the parameters for the L-system to the value you provide. @@ -183,9 +181,8 @@ public struct ParameterizedRandomContextualLSystem: LindenmayerSyst /// - params: The updated value for the parameter type of the L-system. /// - Returns: The L-system with the seed value and parameters value updated. @discardableResult - public func set(seed: UInt64, params: PType) -> Self { - prng.resetRNG(seed: seed) - parameters.update(params) + public func set(seed: UInt64) async -> Self { + await prng.resetRNG(seed: seed) return self } } @@ -203,8 +200,8 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithAll( leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (LC, DC, RC, PType) -> Bool, - produces produceClosure: @escaping (LC, DC, RC, PType, RNGWrapper) -> [Module] + where evalClosure: @Sendable @escaping (LC, DC, RC, PType) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC, RC, PType, RNGWrapper) async -> [Module] ) -> Self where LC: Module, DC: Module, RC: Module { @@ -229,7 +226,7 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithAll( leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (LC, DC, RC, PType, RNGWrapper) -> [Module] + produces produceClosure: @Sendable @escaping (LC, DC, RC, PType, RNGWrapper) async -> [Module] ) -> Self where LC: Module, DC: Module, RC: Module { @@ -254,8 +251,8 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithAll( leftContext: LC.Type, directContext: DC.Type, - where evalClosure: @escaping (LC, DC, PType) -> Bool, - produces produceClosure: @escaping (LC, DC, PType, RNGWrapper) -> [Module] + where evalClosure: @Sendable @escaping (LC, DC, PType) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC, PType, RNGWrapper) async -> [Module] ) -> Self where LC: Module, DC: Module { @@ -279,7 +276,7 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithAll( leftContext: LC.Type, directContext: DC.Type, - produces produceClosure: @escaping (LC, DC, PType, RNGWrapper) -> [Module] + produces produceClosure: @Sendable @escaping (LC, DC, PType, RNGWrapper) async -> [Module] ) -> Self where LC: Module, DC: Module { @@ -304,8 +301,8 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithAll( directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (DC, RC, PType) -> Bool, - produces produceClosure: @escaping (DC, RC, PType, RNGWrapper) -> [Module] + where evalClosure: @Sendable @escaping (DC, RC, PType) -> Bool, + produces produceClosure: @Sendable @escaping (DC, RC, PType, RNGWrapper) async -> [Module] ) -> Self where DC: Module, RC: Module { @@ -329,7 +326,7 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithAll( directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (DC, RC, PType, RNGWrapper) -> [Module] + produces produceClosure: @Sendable @escaping (DC, RC, PType, RNGWrapper) async -> [Module] ) -> Self where DC: Module, RC: Module { @@ -353,8 +350,8 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithAll( directContext: DC.Type, - where evalClosure: @escaping (DC, PType) -> Bool, - produces produceClosure: @escaping (DC, PType, RNGWrapper) -> [Module] + where evalClosure: @Sendable @escaping (DC, PType) -> Bool, + produces produceClosure: @Sendable @escaping (DC, PType, RNGWrapper) async -> [Module] ) -> Self where DC: Module { @@ -377,7 +374,7 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithAll( directContext: DC.Type, - produces produceClosure: @escaping (DC, PType, RNGWrapper) -> [Module] + produces produceClosure: @Sendable @escaping (DC, PType, RNGWrapper) async -> [Module] ) -> Self where DC: Module { @@ -407,8 +404,8 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithParams( leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (LC, DC, RC, PType) -> Bool, - produces produceClosure: @escaping (LC, DC, RC, PType) -> [Module] + where evalClosure: @Sendable @escaping (LC, DC, RC, PType) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC, RC, PType) async -> [Module] ) -> Self where LC: Module, DC: Module, RC: Module { @@ -432,7 +429,7 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithParams( leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (LC, DC, RC, PType) -> [Module] + produces produceClosure: @Sendable @escaping (LC, DC, RC, PType) async -> [Module] ) -> Self where LC: Module, DC: Module, RC: Module { @@ -456,8 +453,8 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithParams( leftContext: LC.Type, directContext: DC.Type, - where evalClosure: @escaping (LC, DC, PType) -> Bool, - produces produceClosure: @escaping (LC, DC, PType) -> [Module] + where evalClosure: @Sendable @escaping (LC, DC, PType) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC, PType) async -> [Module] ) -> Self where LC: Module, DC: Module { @@ -480,7 +477,7 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithParams( leftContext: LC.Type, directContext: DC.Type, - produces produceClosure: @escaping (LC, DC, PType) -> [Module] + produces produceClosure: @Sendable @escaping (LC, DC, PType) async -> [Module] ) -> Self where LC: Module, DC: Module { @@ -504,8 +501,8 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithParams( directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (DC, RC, PType) -> Bool, - produces produceClosure: @escaping (DC, RC, PType) -> [Module] + where evalClosure: @Sendable @escaping (DC, RC, PType) -> Bool, + produces produceClosure: @Sendable @escaping (DC, RC, PType) async -> [Module] ) -> Self where DC: Module, RC: Module { @@ -528,7 +525,7 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithParams( directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (DC, RC, PType) -> [Module] + produces produceClosure: @Sendable @escaping (DC, RC, PType) async -> [Module] ) -> Self where DC: Module, RC: Module { @@ -551,8 +548,8 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithParams( directContext: DC.Type, - where evalClosure: @escaping (DC, PType) -> Bool, - produces produceClosure: @escaping (DC, PType) -> [Module] + where evalClosure: @Sendable @escaping (DC, PType) -> Bool, + produces produceClosure: @Sendable @escaping (DC, PType) async -> [Module] ) -> Self where DC: Module { @@ -574,7 +571,7 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithParams( directContext: DC.Type, - produces produceClosure: @escaping (DC, PType) -> [Module] + produces produceClosure: @Sendable @escaping (DC, PType) async -> [Module] ) -> Self where DC: Module { @@ -603,8 +600,8 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (LC, DC, RC) -> Bool, - produces produceClosure: @escaping (LC, DC, RC, RNGWrapper) -> [Module] + where evalClosure: @Sendable @escaping (LC, DC, RC) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC, RC, RNGWrapper) async -> [Module] ) -> Self where LC: Module, DC: Module, RC: Module { @@ -628,7 +625,7 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (LC, DC, RC, RNGWrapper) -> [Module] + produces produceClosure: @Sendable @escaping (LC, DC, RC, RNGWrapper) async -> [Module] ) -> Self where LC: Module, DC: Module, RC: Module { @@ -652,8 +649,8 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( leftContext: LC.Type, directContext: DC.Type, - where evalClosure: @escaping (LC, DC) -> Bool, - produces produceClosure: @escaping (LC, DC, RNGWrapper) -> [Module] + where evalClosure: @Sendable @escaping (LC, DC) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC, RNGWrapper) async -> [Module] ) -> Self where LC: Module, DC: Module { @@ -676,7 +673,7 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( leftContext: LC.Type, directContext: DC.Type, - produces produceClosure: @escaping (LC, DC, RNGWrapper) -> [Module] + produces produceClosure: @Sendable @escaping (LC, DC, RNGWrapper) async -> [Module] ) -> Self where LC: Module, DC: Module { @@ -701,8 +698,8 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (DC, RC) -> Bool, - produces produceClosure: @escaping (DC, RC, RNGWrapper) -> [Module] + where evalClosure: @Sendable @escaping (DC, RC) -> Bool, + produces produceClosure: @Sendable @escaping (DC, RC, RNGWrapper) async -> [Module] ) -> Self where DC: Module, RC: Module { @@ -725,7 +722,7 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (DC, RC, RNGWrapper) -> [Module] + produces produceClosure: @Sendable @escaping (DC, RC, RNGWrapper) async -> [Module] ) -> Self where DC: Module, RC: Module { @@ -748,8 +745,8 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( directContext: DC.Type, - where evalClosure: @escaping (DC) -> Bool, - produces produceClosure: @escaping (DC, RNGWrapper) -> [Module] + where evalClosure: @Sendable @escaping (DC) -> Bool, + produces produceClosure: @Sendable @escaping (DC, RNGWrapper) async -> [Module] ) -> Self where DC: Module { @@ -771,7 +768,7 @@ public extension ParameterizedRandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( directContext: DC.Type, - produces produceClosure: @escaping (DC, RNGWrapper) -> [Module] + produces produceClosure: @Sendable @escaping (DC, RNGWrapper) async -> [Module] ) -> Self where DC: Module { @@ -795,8 +792,8 @@ public extension ParameterizedRandomContextualLSystem { /// - produces: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(_ direct: DC.Type, - where evalClosure: @escaping (DC) -> Bool, - produces produceClosure: @escaping (DC) -> [Module]) -> Self where DC: Module + where evalClosure: @Sendable @escaping (DC) -> Bool, + produces produceClosure: @Sendable @escaping (DC) -> [Module]) -> Self where DC: Module { let newRule = RewriteRuleDirect(direct: direct, where: evalClosure, produce: produceClosure) var newRuleSet: [Rule] = rules @@ -810,7 +807,7 @@ public extension ParameterizedRandomContextualLSystem { /// - produce: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(_ direct: DC.Type, - produces produceClosure: @escaping (DC) -> [Module]) -> Self where DC: Module + produces produceClosure: @Sendable @escaping (DC) -> [Module]) -> Self where DC: Module { let newRule = RewriteRuleDirect(direct: direct, where: nil, produce: produceClosure) var newRuleSet: [Rule] = rules @@ -825,8 +822,8 @@ public extension ParameterizedRandomContextualLSystem { /// - produces: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(leftContext: LC.Type, directContext: DC.Type, - where evalClosure: @escaping (LC, DC) -> Bool, - produces produceClosure: @escaping (LC, DC) -> [Module]) -> Self where LC: Module, DC: Module + where evalClosure: @Sendable @escaping (LC, DC) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC) -> [Module]) -> Self where LC: Module, DC: Module { let newRule = RewriteRuleLeftDirect(leftType: leftContext, directType: directContext, where: evalClosure, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -840,7 +837,7 @@ public extension ParameterizedRandomContextualLSystem { /// - produce: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(leftContext: LC.Type, directContext: DC.Type, - produces produceClosure: @escaping (LC, DC) -> [Module]) -> Self where LC: Module, DC: Module + produces produceClosure: @Sendable @escaping (LC, DC) -> [Module]) -> Self where LC: Module, DC: Module { let newRule = RewriteRuleLeftDirect(leftType: leftContext, directType: directContext, where: nil, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -855,8 +852,8 @@ public extension ParameterizedRandomContextualLSystem { /// - produces: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (DC, RC) -> Bool, - produces produceClosure: @escaping (DC, RC) -> [Module]) -> Self where DC: Module, RC: Module + where evalClosure: @Sendable @escaping (DC, RC) -> Bool, + produces produceClosure: @Sendable @escaping (DC, RC) -> [Module]) -> Self where DC: Module, RC: Module { let newRule = RewriteRuleDirectRight(directType: directContext, rightType: rightContext, where: evalClosure, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -870,7 +867,7 @@ public extension ParameterizedRandomContextualLSystem { /// - produce: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (DC, RC) -> [Module]) -> Self where DC: Module, RC: Module + produces produceClosure: @Sendable @escaping (DC, RC) -> [Module]) -> Self where DC: Module, RC: Module { let newRule = RewriteRuleDirectRight(directType: directContext, rightType: rightContext, where: nil, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -885,8 +882,8 @@ public extension ParameterizedRandomContextualLSystem { /// - produces: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (LC, DC, RC) -> Bool, - produces produceClosure: @escaping (LC, DC, RC) -> [Module]) -> Self where LC: Module, DC: Module, RC: Module + where evalClosure: @Sendable @escaping (LC, DC, RC) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC, RC) -> [Module]) -> Self where LC: Module, DC: Module, RC: Module { let newRule = RewriteRuleLeftDirectRight(leftType: leftContext, directType: directContext, rightType: rightContext, where: evalClosure, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -900,7 +897,7 @@ public extension ParameterizedRandomContextualLSystem { /// - produce: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (LC, DC, RC) -> [Module]) -> Self where LC: Module, DC: Module, RC: Module + produces produceClosure: @Sendable @escaping (LC, DC, RC) -> [Module]) -> Self where LC: Module, DC: Module, RC: Module { let newRule = RewriteRuleLeftDirectRight(leftType: leftContext, directType: directContext, rightType: rightContext, where: nil, produces: produceClosure) var newRuleSet: [Rule] = rules diff --git a/Sources/Lindenmayer/LSystemTypes/ParametersWrapper.swift b/Sources/Lindenmayer/LSystemTypes/ParametersWrapper.swift deleted file mode 100644 index 622e0899..00000000 --- a/Sources/Lindenmayer/LSystemTypes/ParametersWrapper.swift +++ /dev/null @@ -1,45 +0,0 @@ -// -// ParametersWrapper.swift -// -// -// Created by Joseph Heck on 1/4/22. -// - -import Foundation - -/// A class that provides reference semantics to access an underlying parameter value type that you provide. -/// -/// ## Topics -/// -/// ### Creating a Parameter Type Wrapper -/// -/// - ``ParametersWrapper/init(_:)`` -/// -/// ### Inspecting a Parameter Type Wrapper -/// -/// - ``ParametersWrapper/unwrap()`` -/// -/// ### Updating a Parameter Type Wrapper -/// -/// - ``ParametersWrapper/update(_:)`` -/// -public final class ParametersWrapper { - private var _parameters: PType - - /// Updates the wrapped parameter with the new values that you provide. - /// - Parameter p: The value type with any included parameters. - public func update(_ p: PType) { - _parameters = p - } - - /// Returns the value type that the parameter wrapper encapsulates. - public func unwrap() -> PType { - _parameters - } - - /// Creates a new random number generator wrapper class with the random number generator you provide. - /// - Parameter prng: A random number generator. - public init(_ p: PType) { - _parameters = p - } -} diff --git a/Sources/Lindenmayer/LSystemTypes/RandomContextualLSystem.swift b/Sources/Lindenmayer/LSystemTypes/RandomContextualLSystem.swift index f3595803..5fee025e 100644 --- a/Sources/Lindenmayer/LSystemTypes/RandomContextualLSystem.swift +++ b/Sources/Lindenmayer/LSystemTypes/RandomContextualLSystem.swift @@ -128,8 +128,8 @@ public struct RandomContextualLSystem: LindenmayerSystem where PRNG: Seede /// Resets the L-system to it's initial state, wiping out an existing state while keeping the rules. /// - Returns: A new L-system with it's state reset to the initial state you set when you created the L-system. - public func reset() -> Self { - prng.resetRNG(seed: prng.seed) + public func reset() async -> Self { + await prng.resetRNG(seed: prng.seed) return RandomContextualLSystem(axiom: axiom, state: nil, newStateIndicators: nil, prng: prng, rules: rules) } @@ -137,8 +137,8 @@ public struct RandomContextualLSystem: LindenmayerSystem where PRNG: Seede /// - Parameter seed: The seed value to set within the pseudo-random generator. /// - Returns: The L-system with the seed value updated. @discardableResult - public func setSeed(seed: UInt64) -> Self { - prng.resetRNG(seed: seed) + public func setSeed(seed: UInt64) async -> Self { + await prng.resetRNG(seed: seed) return self } } @@ -156,8 +156,8 @@ public extension RandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (LC, DC, RC) -> Bool, - produces produceClosure: @escaping (LC, DC, RC, RNGWrapper) -> [Module] + where evalClosure: @Sendable @escaping (LC, DC, RC) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC, RC, RNGWrapper) async -> [Module] ) -> Self where LC: Module, DC: Module, RC: Module { @@ -181,7 +181,7 @@ public extension RandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (LC, DC, RC, RNGWrapper) -> [Module] + produces produceClosure: @Sendable @escaping (LC, DC, RC, RNGWrapper) async -> [Module] ) -> Self where LC: Module, DC: Module, RC: Module { @@ -205,8 +205,8 @@ public extension RandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( leftContext: LC.Type, directContext: DC.Type, - where evalClosure: @escaping (LC, DC) -> Bool, - produces produceClosure: @escaping (LC, DC, RNGWrapper) -> [Module] + where evalClosure: @Sendable @escaping (LC, DC) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC, RNGWrapper) async -> [Module] ) -> Self where LC: Module, DC: Module { @@ -229,7 +229,7 @@ public extension RandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( leftContext: LC.Type, directContext: DC.Type, - produces produceClosure: @escaping (LC, DC, RNGWrapper) -> [Module] + produces produceClosure: @Sendable @escaping (LC, DC, RNGWrapper) async -> [Module] ) -> Self where LC: Module, DC: Module { @@ -254,8 +254,8 @@ public extension RandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (DC, RC) -> Bool, - produces produceClosure: @escaping (DC, RC, RNGWrapper) -> [Module] + where evalClosure: @Sendable @escaping (DC, RC) -> Bool, + produces produceClosure: @Sendable @escaping (DC, RC, RNGWrapper) async -> [Module] ) -> Self where DC: Module, RC: Module { @@ -278,7 +278,7 @@ public extension RandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (DC, RC, RNGWrapper) -> [Module] + produces produceClosure: @Sendable @escaping (DC, RC, RNGWrapper) async -> [Module] ) -> Self where DC: Module, RC: Module { @@ -301,8 +301,8 @@ public extension RandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( directContext: DC.Type, - where evalClosure: @escaping (DC) -> Bool, - produces produceClosure: @escaping (DC, RNGWrapper) -> [Module] + where evalClosure: @Sendable @escaping (DC) -> Bool, + produces produceClosure: @Sendable @escaping (DC, RNGWrapper) async -> [Module] ) -> Self where DC: Module { @@ -324,7 +324,7 @@ public extension RandomContextualLSystem { /// - Returns: A new L-System with the additional rule added. func rewriteWithRNG( directContext: DC.Type, - produces produceClosure: @escaping (DC, RNGWrapper) -> [Module] + produces produceClosure: @Sendable @escaping (DC, RNGWrapper) async -> [Module] ) -> Self where DC: Module { @@ -350,8 +350,8 @@ public extension RandomContextualLSystem { /// - produces: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(_ direct: DC.Type, - where evalClosure: @escaping (DC) -> Bool, - produces produceClosure: @escaping (DC) -> [Module]) -> Self where DC: Module + where evalClosure: @Sendable @escaping (DC) -> Bool, + produces produceClosure: @Sendable @escaping (DC) -> [Module]) -> Self where DC: Module { let newRule = RewriteRuleDirect(direct: direct, where: evalClosure, produce: produceClosure) var newRuleSet: [Rule] = rules @@ -365,7 +365,7 @@ public extension RandomContextualLSystem { /// - produce: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(_ direct: DC.Type, - produces produceClosure: @escaping (DC) -> [Module]) -> Self where DC: Module + produces produceClosure: @Sendable @escaping (DC) -> [Module]) -> Self where DC: Module { let newRule = RewriteRuleDirect(direct: direct, where: nil, produce: produceClosure) var newRuleSet: [Rule] = rules @@ -380,8 +380,8 @@ public extension RandomContextualLSystem { /// - produces: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(leftContext: LC.Type, directContext: DC.Type, - where evalClosure: @escaping (LC, DC) -> Bool, - produces produceClosure: @escaping (LC, DC) -> [Module]) -> Self where LC: Module, DC: Module + where evalClosure: @Sendable @escaping (LC, DC) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC) -> [Module]) -> Self where LC: Module, DC: Module { let newRule = RewriteRuleLeftDirect(leftType: leftContext, directType: directContext, where: evalClosure, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -395,7 +395,7 @@ public extension RandomContextualLSystem { /// - produce: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(leftContext: LC.Type, directContext: DC.Type, - produces produceClosure: @escaping (LC, DC) -> [Module]) -> Self where LC: Module, DC: Module + produces produceClosure: @Sendable @escaping (LC, DC) -> [Module]) -> Self where LC: Module, DC: Module { let newRule = RewriteRuleLeftDirect(leftType: leftContext, directType: directContext, where: nil, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -410,8 +410,8 @@ public extension RandomContextualLSystem { /// - produces: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (DC, RC) -> Bool, - produces produceClosure: @escaping (DC, RC) -> [Module]) -> Self where DC: Module, RC: Module + where evalClosure: @Sendable @escaping (DC, RC) -> Bool, + produces produceClosure: @Sendable @escaping (DC, RC) -> [Module]) -> Self where DC: Module, RC: Module { let newRule = RewriteRuleDirectRight(directType: directContext, rightType: rightContext, where: evalClosure, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -425,7 +425,7 @@ public extension RandomContextualLSystem { /// - produce: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (DC, RC) -> [Module]) -> Self where DC: Module, RC: Module + produces produceClosure: @Sendable @escaping (DC, RC) -> [Module]) -> Self where DC: Module, RC: Module { let newRule = RewriteRuleDirectRight(directType: directContext, rightType: rightContext, where: nil, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -440,8 +440,8 @@ public extension RandomContextualLSystem { /// - produces: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - where evalClosure: @escaping (LC, DC, RC) -> Bool, - produces produceClosure: @escaping (LC, DC, RC) -> [Module]) -> Self where LC: Module, DC: Module, RC: Module + where evalClosure: @Sendable @escaping (LC, DC, RC) -> Bool, + produces produceClosure: @Sendable @escaping (LC, DC, RC) -> [Module]) -> Self where LC: Module, DC: Module, RC: Module { let newRule = RewriteRuleLeftDirectRight(leftType: leftContext, directType: directContext, rightType: rightContext, where: evalClosure, produces: produceClosure) var newRuleSet: [Rule] = rules @@ -455,7 +455,7 @@ public extension RandomContextualLSystem { /// - produce: A closure that you provide that returns a list of modules to replace the matching module. /// - Returns: A new L-System with the additional rule added. func rewrite(leftContext: LC.Type, directContext: DC.Type, rightContext: RC.Type, - produces produceClosure: @escaping (LC, DC, RC) -> [Module]) -> Self where LC: Module, DC: Module, RC: Module + produces produceClosure: @Sendable @escaping (LC, DC, RC) -> [Module]) -> Self where LC: Module, DC: Module, RC: Module { let newRule = RewriteRuleLeftDirectRight(leftType: leftContext, directType: directContext, rightType: rightContext, where: nil, produces: produceClosure) var newRuleSet: [Rule] = rules diff --git a/Sources/Lindenmayer/Lindenmayer.docc/Lindenmayer.md b/Sources/Lindenmayer/Lindenmayer.docc/Lindenmayer.md index 3d87e323..bb527bb3 100644 --- a/Sources/Lindenmayer/Lindenmayer.docc/Lindenmayer.md +++ b/Sources/Lindenmayer/Lindenmayer.docc/Lindenmayer.md @@ -28,7 +28,6 @@ To get support for using this package, see the [Discussions on Github](https://g - ``ParameterizedRandomContextualLSystem`` - ``LindenmayerSystem`` - ``ModuleSet`` -- ``ParametersWrapper`` ### Modules diff --git a/Sources/Lindenmayer/LindenmayerSystem.swift b/Sources/Lindenmayer/LindenmayerSystem.swift index ac15243f..51f3584f 100644 --- a/Sources/Lindenmayer/LindenmayerSystem.swift +++ b/Sources/Lindenmayer/LindenmayerSystem.swift @@ -52,13 +52,13 @@ public protocol LindenmayerSystem: Sendable { /// The L-system evolved by a number of iterations you provide. /// - Parameter iterations: The number of times to evolve the L-system. /// - Returns: The updated L-system from the number of evolutions you provided. - func evolved(iterations: Int) -> Self + func evolved(iterations: Int) async -> Self /// Returns a new L-system after processing the current state against the rules to generate a new state sequence. - func evolve() -> Self + func evolve() async -> Self /// Returns a new L-system reset to its original state. - func reset() -> Self + func reset() async -> Self /// Returns a set of modules around the index location you provide. /// - Parameter atIndex: The index location of the state of the current L-system. @@ -92,7 +92,7 @@ public extension LindenmayerSystem { var rightInstance: (any Module)? = nil if state.count > atIndex + 1 { - let rightInstance = state[atIndex + 1] + rightInstance = state[atIndex + 1] } return ModuleSet(leftInstance: leftInstance, directInstance: strict, rightInstance: rightInstance) @@ -103,7 +103,7 @@ public extension LindenmayerSystem { /// The Lindermayer system iterates through the rules provided, applying the first rule that matches the state from the rule to the current state of the system. /// When applying the rule, the element that matched is replaced with what the rule returns from ``Rule/produce(_:)``. /// - Returns: An updated Lindenmayer system. - func evolve() -> Self { + func evolve() async -> Self { // Performance is O(n)(z) with the (n) number of atoms in the state and (z) number of rules to apply. // TODO(heckj): revisit this with async methods in mind, creating tasks for each iteration // in order to run the whole suite of the state in parallel for a new result. Await the whole @@ -120,7 +120,7 @@ public extension LindenmayerSystem { if let foundRule = maybeRule { // If a rule was found, then use it to generate the modules that // replace this element in the sequence. - let newModules = foundRule.produce(moduleSet) + let newModules = await foundRule.produce(moduleSet) newState.append(contentsOf: newModules) for _ in newModules { newStateIndicatorArray.append(true) @@ -141,10 +141,10 @@ public extension LindenmayerSystem { /// The L-system evolved by a number of iterations you provide. /// - Parameter iterations: The number of times to evolve the L-system. /// - Returns: The updated L-system from the number of evolutions you provided. - func evolved(iterations: Int = 1) -> Self { + func evolved(iterations: Int = 1) async -> Self { var lsys: Self = self for _ in 0 ..< iterations { - lsys = lsys.evolve() + lsys = await lsys.evolve() } return lsys } diff --git a/Sources/Lindenmayer/PRNG/RNGWrapper.swift b/Sources/Lindenmayer/PRNG/RNGWrapper.swift index 99c01fc5..a86a80eb 100644 --- a/Sources/Lindenmayer/PRNG/RNGWrapper.swift +++ b/Sources/Lindenmayer/PRNG/RNGWrapper.swift @@ -24,7 +24,7 @@ import Foundation /// /// - ``RNGWrapper/resetRNG(seed:)`` /// -public final class RNGWrapper where PRNG: SeededRandomNumberGenerator { +public actor RNGWrapper: Sendable where PRNG: SeededRandomNumberGenerator { private var _prng: PRNG #if DEBUG var _invokeCount: UInt64 = 0 diff --git a/Sources/Lindenmayer/PRNG/SeededRandomNumberGenerator.swift b/Sources/Lindenmayer/PRNG/SeededRandomNumberGenerator.swift index cc3eca4c..e15c699f 100644 --- a/Sources/Lindenmayer/PRNG/SeededRandomNumberGenerator.swift +++ b/Sources/Lindenmayer/PRNG/SeededRandomNumberGenerator.swift @@ -11,7 +11,7 @@ import Foundation /// The protocol includes an adjustable position property that represents the current location within the space of random numbers that the random number generates. /// The seed value is preserved and unchanged, allowing the seeded random number generator to be interrogated and replicated. /// When applied to a pseudo-random number generator, with a given seed and position, the next random number should be completely deterministic. -public protocol SeededRandomNumberGenerator: RandomNumberGenerator { +public protocol SeededRandomNumberGenerator: RandomNumberGenerator, Sendable { /// The seed for the random number generator. var seed: UInt64 { get } diff --git a/Sources/Lindenmayer/PRNG/Xoshiro.swift b/Sources/Lindenmayer/PRNG/Xoshiro.swift index bc9cb0b4..5ef114ea 100644 --- a/Sources/Lindenmayer/PRNG/Xoshiro.swift +++ b/Sources/Lindenmayer/PRNG/Xoshiro.swift @@ -19,7 +19,7 @@ /// A pseudo-random number generator that produces random numbers based on an initial seed. /// /// The algorithm for the generation is xoshiro256, based on the [public domain implementation](http://xoshiro.di.unimi.it). -public struct Xoshiro: SeededRandomNumberGenerator { +public struct Xoshiro: SeededRandomNumberGenerator, Sendable { /// The initial seed for pseuo-random number generation. public let seed: UInt64 diff --git a/Sources/Lindenmayer/Rules/RewriteRuleDirect.swift b/Sources/Lindenmayer/Rules/RewriteRuleDirect.swift index f0a9ce42..c3b4c8d6 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleDirect.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleDirect.swift @@ -29,13 +29,13 @@ import Foundation /// public struct RewriteRuleDirect: Rule where DC: Module { /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((DC) -> Bool)? + public var parametricEval: (@Sendable (DC) -> Bool)? /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias singleMatchProducesList = (DC) -> [Module] + public typealias SingleMatchProducesList = @Sendable (DC) -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: singleMatchProducesList + public let produceClosure: SingleMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingType: DC.Type @@ -47,7 +47,7 @@ public struct RewriteRuleDirect: Rule where DC: Module { /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(direct: DC.Type, where _: ((DC) -> Bool)?, - produce produceClosure: @escaping singleMatchProducesList) + produce produceClosure: @escaping SingleMatchProducesList) { matchingType = direct self.produceClosure = produceClosure diff --git a/Sources/Lindenmayer/Rules/RewriteRuleDirectDefines.swift b/Sources/Lindenmayer/Rules/RewriteRuleDirectDefines.swift index e78f41b5..3ee0e0e9 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleDirectDefines.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleDirectDefines.swift @@ -28,18 +28,18 @@ import Foundation /// - ``singleMatchProducesList`` /// -public struct RewriteRuleDirectDefines: Rule where DC: Module { +public struct RewriteRuleDirectDefines: Rule where DC: Module, PType: Sendable { /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((DC, PType) -> Bool)? - + public let parametricEval: Eval? + public typealias Eval = @Sendable (DC, PType) -> Bool /// The set of parameters provided by the L-system for rule evaluation and production. - var parameters: ParametersWrapper + let parameters: PType /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias singleMatchProducesList = (DC, PType) -> [Module] + public typealias SingleMatchProducesList = @Sendable (DC, PType) async -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: singleMatchProducesList + public let produceClosure: SingleMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingType: DC.Type @@ -50,13 +50,14 @@ public struct RewriteRuleDirectDefines: Rule where DC: Module { /// - prng: An optional psuedo-random number generator to use for stochastic rule productions. /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(directType direct: DC.Type, - parameters: ParametersWrapper, - where _: ((DC, PType) -> Bool)?, - produces singleModuleProduce: @escaping singleMatchProducesList) + parameters: PType, + where eval: Eval?, + produces singleModuleProduce: @escaping SingleMatchProducesList) { matchingType = direct self.parameters = parameters produceClosure = singleModuleProduce + parametricEval = eval } /// Determines if a rule should be evaluated while processing the individual atoms of an L-system state sequence. @@ -75,7 +76,7 @@ public struct RewriteRuleDirectDefines: Rule where DC: Module { guard let directInstance = matchSet.directInstance as? DC else { return false } - return additionalEval(directInstance, parameters.unwrap()) + return additionalEval(directInstance, parameters) } return true @@ -84,11 +85,11 @@ public struct RewriteRuleDirectDefines: Rule where DC: Module { /// Invokes the rule's produce closure with the modules provided. /// - Parameter matchSet: The module instances to pass to the produce closure. /// - Returns: A sequence of modules that the produce closure returns. - public func produce(_ matchSet: ModuleSet) -> [Module] { + public func produce(_ matchSet: ModuleSet) async -> [Module] { guard let directInstance = matchSet.directInstance as? DC else { return [] } - return produceClosure(directInstance, parameters.unwrap()) + return await produceClosure(directInstance, parameters) } } diff --git a/Sources/Lindenmayer/Rules/RewriteRuleDirectDefinesRNG.swift b/Sources/Lindenmayer/Rules/RewriteRuleDirectDefinesRNG.swift index 390263d3..5d8d38c2 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleDirectDefinesRNG.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleDirectDefinesRNG.swift @@ -28,21 +28,21 @@ import Foundation /// - ``singleMatchProducesList`` /// -public struct RewriteRuleDirectDefinesRNG: Rule where DC: Module, PRNG: SeededRandomNumberGenerator { +public struct RewriteRuleDirectDefinesRNG: Rule where DC: Module, PRNG: SeededRandomNumberGenerator, PType: Sendable { /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((DC, PType) -> Bool)? - + public let parametricEval: Eval? + public typealias Eval = @Sendable (DC, PType) -> Bool /// The set of parameters provided by the L-system for rule evaluation and production. - var parameters: ParametersWrapper + let parameters: PType /// A psuedo-random number generator to use for stochastic rule productions. var prng: RNGWrapper /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias singleMatchProducesList = (DC, PType, RNGWrapper) -> [Module] + public typealias SingleMatchProducesList = @Sendable (DC, PType, RNGWrapper) async -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: singleMatchProducesList + public let produceClosure: SingleMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingType: DC.Type @@ -53,15 +53,16 @@ public struct RewriteRuleDirectDefinesRNG: Rule where DC: Modul /// - prng: An optional psuedo-random number generator to use for stochastic rule productions. /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(directType direct: DC.Type, - parameters: ParametersWrapper, + parameters: PType, prng: RNGWrapper, - where _: ((DC, PType) -> Bool)?, - produces singleModuleProduce: @escaping singleMatchProducesList) + where eval: Eval?, + produces singleModuleProduce: @escaping SingleMatchProducesList) { matchingType = direct self.parameters = parameters self.prng = prng produceClosure = singleModuleProduce + parametricEval = eval } /// Determines if a rule should be evaluated while processing the individual atoms of an L-system state sequence. @@ -81,7 +82,7 @@ public struct RewriteRuleDirectDefinesRNG: Rule where DC: Modul return false } - return additionalEval(directInstance, parameters.unwrap()) + return additionalEval(directInstance, parameters) } return true @@ -90,11 +91,11 @@ public struct RewriteRuleDirectDefinesRNG: Rule where DC: Modul /// Invokes the rule's produce closure with the modules provided. /// - Parameter matchSet: The module instances to pass to the produce closure. /// - Returns: A sequence of modules that the produce closure returns. - public func produce(_ matchSet: ModuleSet) -> [Module] { + public func produce(_ matchSet: ModuleSet) async -> [Module] { guard let directInstance = matchSet.directInstance as? DC else { return [] } - return produceClosure(directInstance, parameters.unwrap(), prng) + return await produceClosure(directInstance, parameters, prng) } } diff --git a/Sources/Lindenmayer/Rules/RewriteRuleDirectRNG.swift b/Sources/Lindenmayer/Rules/RewriteRuleDirectRNG.swift index 778becea..be882308 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleDirectRNG.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleDirectRNG.swift @@ -30,16 +30,16 @@ import Foundation public struct RewriteRuleDirectRNG: Rule where DC: Module, PRNG: SeededRandomNumberGenerator { /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((DC) -> Bool)? + public var parametricEval: (@Sendable (DC) -> Bool)? /// A psuedo-random number generator to use for stochastic rule productions. var prng: RNGWrapper /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias singleMatchProducesList = (DC, RNGWrapper) -> [Module] + public typealias SingleMatchProducesList = @Sendable (DC, RNGWrapper) async -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: singleMatchProducesList + public let produceClosure: SingleMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingType: DC.Type @@ -51,11 +51,12 @@ public struct RewriteRuleDirectRNG: Rule where DC: Module, PRNG: Seede /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(directType direct: DC.Type, prng: RNGWrapper, - where _: ((DC) -> Bool)?, - produces singleModuleProduce: @escaping singleMatchProducesList) + where eval: (@Sendable (DC) -> Bool)?, + produces singleModuleProduce: @escaping SingleMatchProducesList) { matchingType = direct self.prng = prng + parametricEval = eval produceClosure = singleModuleProduce } @@ -85,11 +86,11 @@ public struct RewriteRuleDirectRNG: Rule where DC: Module, PRNG: Seede /// Invokes the rule's produce closure with the modules provided. /// - Parameter matchSet: The module instances to pass to the produce closure. /// - Returns: A sequence of modules that the produce closure returns. - public func produce(_ matchSet: ModuleSet) -> [Module] { + public func produce(_ matchSet: ModuleSet) async -> [Module] { guard let directInstance = matchSet.directInstance as? DC else { return [] } - return produceClosure(directInstance, prng) + return await produceClosure(directInstance, prng) } } diff --git a/Sources/Lindenmayer/Rules/RewriteRuleDirectRight.swift b/Sources/Lindenmayer/Rules/RewriteRuleDirectRight.swift index 1812e0e4..1d980a9d 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleDirectRight.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleDirectRight.swift @@ -29,13 +29,13 @@ import Foundation /// public struct RewriteRuleDirectRight: Rule where DC: Module, RC: Module { /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((DC, RC) -> Bool)? + public var parametricEval: (@Sendable (DC, RC) -> Bool)? /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias rightMatchProducesList = (DC, RC) -> [Module] + public typealias RightMatchProducesList = @Sendable (DC, RC) -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: rightMatchProducesList + public let produceClosure: RightMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingTypes: (DC.Type, RC.Type) @@ -47,7 +47,7 @@ public struct RewriteRuleDirectRight: Rule where DC: Module, RC: Module /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(directType: DC.Type, rightType: RC.Type, where _: ((DC, RC) -> Bool)?, - produces produceClosure: @escaping rightMatchProducesList) + produces produceClosure: @escaping RightMatchProducesList) { matchingTypes = (directType, rightType) self.produceClosure = produceClosure diff --git a/Sources/Lindenmayer/Rules/RewriteRuleDirectRightDefines.swift b/Sources/Lindenmayer/Rules/RewriteRuleDirectRightDefines.swift index 11546ed8..f2671314 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleDirectRightDefines.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleDirectRightDefines.swift @@ -27,18 +27,18 @@ import Foundation /// - ``produceClosure`` /// - ``combinationMatchProducesList`` /// -public struct RewriteRuleDirectRightDefines: Rule where DC: Module, RC: Module { +public struct RewriteRuleDirectRightDefines: Rule where DC: Module, RC: Module, PType: Sendable { /// The set of parameters provided by the L-system for rule evaluation and production. - var parameters: ParametersWrapper + let parameters: PType /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((DC, RC, PType) -> Bool)? - + public let parametricEval: Eval? + public typealias Eval = @Sendable (DC, RC, PType) -> Bool /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias combinationMatchProducesList = (DC, RC, PType) -> [Module] + public typealias CombinationMatchProducesList = @Sendable (DC, RC, PType) async -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: combinationMatchProducesList + public let produceClosure: CombinationMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingTypes: (DC.Type, RC.Type) @@ -49,13 +49,14 @@ public struct RewriteRuleDirectRightDefines: Rule where DC: Modul /// - prng: An optional psuedo-random number generator to use for stochastic rule productions. /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(directType: DC.Type, rightType: RC.Type, - parameters: ParametersWrapper, - where _: ((DC, RC, PType) -> Bool)?, - produces produceClosure: @escaping combinationMatchProducesList) + parameters: PType, + where eval: Eval?, + produces produceClosure: @escaping CombinationMatchProducesList) { matchingTypes = (directType, rightType) self.parameters = parameters self.produceClosure = produceClosure + parametricEval = eval } /// Determines if a rule should be evaluated while processing the individual atoms of an L-system state sequence. @@ -78,7 +79,7 @@ public struct RewriteRuleDirectRightDefines: Rule where DC: Modul else { return false } - return additionalEval(directInstance, rightInstance, parameters.unwrap()) + return additionalEval(directInstance, rightInstance, parameters) } return true @@ -87,13 +88,13 @@ public struct RewriteRuleDirectRightDefines: Rule where DC: Modul /// Invokes the rule's produce closure with the modules provided. /// - Parameter matchSet: The module instances to pass to the produce closure. /// - Returns: A sequence of modules that the produce closure returns. - public func produce(_ matchSet: ModuleSet) -> [Module] { + public func produce(_ matchSet: ModuleSet) async -> [Module] { guard let directInstance = matchSet.directInstance as? DC, let rightInstance = matchSet.rightInstance as? RC else { return [] } - return produceClosure(directInstance, rightInstance, parameters.unwrap()) + return await produceClosure(directInstance, rightInstance, parameters) } } diff --git a/Sources/Lindenmayer/Rules/RewriteRuleDirectRightDefinesRNG.swift b/Sources/Lindenmayer/Rules/RewriteRuleDirectRightDefinesRNG.swift index e769e41f..061fb856 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleDirectRightDefinesRNG.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleDirectRightDefinesRNG.swift @@ -27,21 +27,21 @@ import Foundation /// - ``produceClosure`` /// - ``combinationMatchProducesList`` /// -public struct RewriteRuleDirectRightDefinesRNG: Rule where DC: Module, RC: Module, PRNG: SeededRandomNumberGenerator { +public struct RewriteRuleDirectRightDefinesRNG: Rule where DC: Module, RC: Module, PRNG: SeededRandomNumberGenerator, PType: Sendable { /// The set of parameters provided by the L-system for rule evaluation and production. - var parameters: ParametersWrapper + let parameters: PType /// A psuedo-random number generator to use for stochastic rule productions. var prng: RNGWrapper /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((DC, RC, PType) -> Bool)? - + public let parametricEval: Eval? + public typealias Eval = @Sendable (DC, RC, PType) -> Bool /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias combinationMatchProducesList = (DC, RC, PType, RNGWrapper) -> [Module] + public typealias CombinationMatchProducesList = @Sendable (DC, RC, PType, RNGWrapper) async -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: combinationMatchProducesList + public let produceClosure: CombinationMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingTypes: (DC.Type, RC.Type) @@ -52,15 +52,16 @@ public struct RewriteRuleDirectRightDefinesRNG: Rule where /// - prng: An optional psuedo-random number generator to use for stochastic rule productions. /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(directType: DC.Type, rightType: RC.Type, - parameters: ParametersWrapper, + parameters: PType, prng: RNGWrapper, - where _: ((DC, RC, PType) -> Bool)?, - produces produceClosure: @escaping combinationMatchProducesList) + where eval: Eval?, + produces produceClosure: @escaping CombinationMatchProducesList) { matchingTypes = (directType, rightType) self.parameters = parameters self.prng = prng self.produceClosure = produceClosure + parametricEval = eval } /// Determines if a rule should be evaluated while processing the individual atoms of an L-system state sequence. @@ -83,7 +84,7 @@ public struct RewriteRuleDirectRightDefinesRNG: Rule where else { return false } - return additionalEval(directInstance, rightInstance, parameters.unwrap()) + return additionalEval(directInstance, rightInstance, parameters) } return true @@ -92,13 +93,13 @@ public struct RewriteRuleDirectRightDefinesRNG: Rule where /// Invokes the rule's produce closure with the modules provided. /// - Parameter matchSet: The module instances to pass to the produce closure. /// - Returns: A sequence of modules that the produce closure returns. - public func produce(_ matchSet: ModuleSet) -> [Module] { + public func produce(_ matchSet: ModuleSet) async -> [Module] { guard let directInstance = matchSet.directInstance as? DC, let rightInstance = matchSet.rightInstance as? RC else { return [] } - return produceClosure(directInstance, rightInstance, parameters.unwrap(), prng) + return await produceClosure(directInstance, rightInstance, parameters, prng) } } diff --git a/Sources/Lindenmayer/Rules/RewriteRuleDirectRightRNG.swift b/Sources/Lindenmayer/Rules/RewriteRuleDirectRightRNG.swift index 85907944..bd79173d 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleDirectRightRNG.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleDirectRightRNG.swift @@ -32,13 +32,13 @@ public struct RewriteRuleDirectRightRNG: Rule where DC: Module, RC var prng: RNGWrapper /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((DC, RC) -> Bool)? + public var parametricEval: (@Sendable (DC, RC) -> Bool)? /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias combinationMatchProducesList = (DC, RC, RNGWrapper) -> [Module] + public typealias CombinationMatchProducesList = @Sendable (DC, RC, RNGWrapper) async -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: combinationMatchProducesList + public let produceClosure: CombinationMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingTypes: (DC.Type, RC.Type) @@ -50,11 +50,12 @@ public struct RewriteRuleDirectRightRNG: Rule where DC: Module, RC /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(directType: DC.Type, rightType: RC.Type, prng: RNGWrapper, - where _: ((DC, RC) -> Bool)?, - produces produceClosure: @escaping combinationMatchProducesList) + where eval: (@Sendable (DC, RC) -> Bool)?, + produces produceClosure: @escaping CombinationMatchProducesList) { matchingTypes = (directType, rightType) self.prng = prng + parametricEval = eval self.produceClosure = produceClosure } @@ -87,13 +88,13 @@ public struct RewriteRuleDirectRightRNG: Rule where DC: Module, RC /// Invokes the rule's produce closure with the modules provided. /// - Parameter matchSet: The module instances to pass to the produce closure. /// - Returns: A sequence of modules that the produce closure returns. - public func produce(_ matchSet: ModuleSet) -> [Module] { + public func produce(_ matchSet: ModuleSet) async -> [Module] { guard let directInstance = matchSet.directInstance as? DC, let rightInstance = matchSet.rightInstance as? RC else { return [] } - return produceClosure(directInstance, rightInstance, prng) + return await produceClosure(directInstance, rightInstance, prng) } } diff --git a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirect.swift b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirect.swift index 6e597cd3..334fa33a 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirect.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirect.swift @@ -29,13 +29,13 @@ import Foundation /// public struct RewriteRuleLeftDirect: Rule where LC: Module, DC: Module { /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((LC, DC) -> Bool)? + public var parametricEval: (@Sendable (LC, DC) -> Bool)? /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias leftMatchProducesList = (LC, DC) -> [Module] + public typealias LeftMatchProducesList = @Sendable (LC, DC) -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: leftMatchProducesList + public let produceClosure: LeftMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingTypes: (LC.Type, DC.Type) @@ -47,7 +47,7 @@ public struct RewriteRuleLeftDirect: Rule where LC: Module, DC: Module { /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(leftType: LC.Type, directType: DC.Type, where _: ((LC, DC) -> Bool)?, - produces produceClosure: @escaping leftMatchProducesList) + produces produceClosure: @escaping LeftMatchProducesList) { matchingTypes = (leftType, directType) self.produceClosure = produceClosure diff --git a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectDefines.swift b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectDefines.swift index ff936f94..9bbffde7 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectDefines.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectDefines.swift @@ -27,18 +27,18 @@ import Foundation /// - ``produceClosure`` /// - ``combinationMatchProducesList`` /// -public struct RewriteRuleLeftDirectDefines: Rule where LC: Module, DC: Module { +public struct RewriteRuleLeftDirectDefines: Rule where LC: Module, DC: Module, PType: Sendable { /// The set of parameters provided by the L-system for rule evaluation and production. - var parameters: ParametersWrapper + let parameters: PType /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((LC, DC, PType) -> Bool)? - + public let parametricEval: Eval? + public typealias Eval = @Sendable (LC, DC, PType) -> Bool /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias combinationMatchProducesList = (LC, DC, PType) -> [Module] + public typealias CombinationMatchProducesList = @Sendable (LC, DC, PType) async -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: combinationMatchProducesList + public let produceClosure: CombinationMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingTypes: (LC.Type, DC.Type) @@ -49,13 +49,14 @@ public struct RewriteRuleLeftDirectDefines: Rule where LC: Module /// - prng: An optional psuedo-random number generator to use for stochastic rule productions. /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(leftType: LC.Type, directType: DC.Type, - parameters: ParametersWrapper, - where _: ((LC, DC, PType) -> Bool)?, - produces produceClosure: @escaping combinationMatchProducesList) + parameters: PType, + where eval: Eval?, + produces produceClosure: @escaping CombinationMatchProducesList) { matchingTypes = (leftType, directType) self.parameters = parameters self.produceClosure = produceClosure + parametricEval = eval } /// Determines if a rule should be evaluated while processing the individual atoms of an L-system state sequence. @@ -79,7 +80,7 @@ public struct RewriteRuleLeftDirectDefines: Rule where LC: Module else { return false } - return additionalEval(leftInstance, directInstance, parameters.unwrap()) + return additionalEval(leftInstance, directInstance, parameters) } return true @@ -88,14 +89,14 @@ public struct RewriteRuleLeftDirectDefines: Rule where LC: Module /// Invokes the rule's produce closure with the modules provided. /// - Parameter matchSet: The module instances to pass to the produce closure. /// - Returns: A sequence of modules that the produce closure returns. - public func produce(_ matchSet: ModuleSet) -> [Module] { + public func produce(_ matchSet: ModuleSet) async -> [Module] { guard let leftInstance = matchSet.leftInstance as? LC, let directInstance = matchSet.directInstance as? DC else { return [] } - return produceClosure(leftInstance, directInstance, parameters.unwrap()) + return await produceClosure(leftInstance, directInstance, parameters) } } diff --git a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectDefinesRNG.swift b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectDefinesRNG.swift index ce8c55c2..66f68f4e 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectDefinesRNG.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectDefinesRNG.swift @@ -28,21 +28,21 @@ import Foundation /// - ``combinationMatchProducesList`` /// -public struct RewriteRuleLeftDirectDefinesRNG: Rule where LC: Module, DC: Module, PRNG: SeededRandomNumberGenerator { +public struct RewriteRuleLeftDirectDefinesRNG: Rule where LC: Module, DC: Module, PRNG: SeededRandomNumberGenerator, PType: Sendable { /// The set of parameters provided by the L-system for rule evaluation and production. - var parameters: ParametersWrapper + let parameters: PType /// A psuedo-random number generator to use for stochastic rule productions. var prng: RNGWrapper /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((LC, DC, PType) -> Bool)? - + public let parametricEval: Eval? + public typealias Eval = @Sendable (LC, DC, PType) -> Bool /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias combinationMatchProducesList = (LC, DC, PType, RNGWrapper) -> [Module] + public typealias CombinationMatchProducesList = @Sendable (LC, DC, PType, RNGWrapper) async -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: combinationMatchProducesList + public let produceClosure: CombinationMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingTypes: (LC.Type, DC.Type) @@ -53,15 +53,16 @@ public struct RewriteRuleLeftDirectDefinesRNG: Rule where L /// - prng: An optional psuedo-random number generator to use for stochastic rule productions. /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(leftType: LC.Type, directType: DC.Type, - parameters: ParametersWrapper, + parameters: PType, prng: RNGWrapper, - where _: ((LC, DC, PType) -> Bool)?, - produces produceClosure: @escaping combinationMatchProducesList) + where eval: Eval?, + produces produceClosure: @escaping CombinationMatchProducesList) { matchingTypes = (leftType, directType) self.parameters = parameters self.prng = prng self.produceClosure = produceClosure + parametricEval = eval } /// Determines if a rule should be evaluated while processing the individual atoms of an L-system state sequence. @@ -85,7 +86,7 @@ public struct RewriteRuleLeftDirectDefinesRNG: Rule where L else { return false } - return additionalEval(leftInstance, directInstance, parameters.unwrap()) + return additionalEval(leftInstance, directInstance, parameters) } return true @@ -94,13 +95,13 @@ public struct RewriteRuleLeftDirectDefinesRNG: Rule where L /// Invokes the rule's produce closure with the modules provided. /// - Parameter matchSet: The module instances to pass to the produce closure. /// - Returns: A sequence of modules that the produce closure returns. - public func produce(_ matchSet: ModuleSet) -> [Module] { + public func produce(_ matchSet: ModuleSet) async -> [Module] { guard let leftInstance = matchSet.leftInstance as? LC, let directInstance = matchSet.directInstance as? DC else { return [] } - return produceClosure(leftInstance, directInstance, parameters.unwrap(), prng) + return await produceClosure(leftInstance, directInstance, parameters, prng) } } diff --git a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRNG.swift b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRNG.swift index 87341ef9..be22e8d2 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRNG.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRNG.swift @@ -32,13 +32,13 @@ public struct RewriteRuleLeftDirectRNG: Rule where LC: Module, DC: var prng: RNGWrapper /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((LC, DC) -> Bool)? + public var parametricEval: (@Sendable (LC, DC) -> Bool)? /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias combinationMatchProducesList = (LC, DC, RNGWrapper) -> [Module] + public typealias CombinationMatchProducesList = @Sendable (LC, DC, RNGWrapper) async -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: combinationMatchProducesList + public let produceClosure: CombinationMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingTypes: (LC.Type, DC.Type) @@ -51,7 +51,7 @@ public struct RewriteRuleLeftDirectRNG: Rule where LC: Module, DC: public init(leftType: LC.Type, directType: DC.Type, prng: RNGWrapper, where _: ((LC, DC) -> Bool)?, - produces produceClosure: @escaping combinationMatchProducesList) + produces produceClosure: @escaping CombinationMatchProducesList) { matchingTypes = (leftType, directType) self.prng = prng @@ -88,13 +88,13 @@ public struct RewriteRuleLeftDirectRNG: Rule where LC: Module, DC: /// Invokes the rule's produce closure with the modules provided. /// - Parameter matchSet: The module instances to pass to the produce closure. /// - Returns: A sequence of modules that the produce closure returns. - public func produce(_ matchSet: ModuleSet) -> [Module] { + public func produce(_ matchSet: ModuleSet) async -> [Module] { guard let leftInstance = matchSet.leftInstance as? LC, let directInstance = matchSet.directInstance as? DC else { return [] } - return produceClosure(leftInstance, directInstance, prng) + return await produceClosure(leftInstance, directInstance, prng) } } diff --git a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRight.swift b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRight.swift index a33914e8..75ac9afd 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRight.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRight.swift @@ -29,13 +29,13 @@ import Foundation /// public struct RewriteRuleLeftDirectRight: Rule where LC: Module, DC: Module, RC: Module { /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((LC, DC, RC) -> Bool)? + public var parametricEval: (@Sendable (LC, DC, RC) -> Bool)? /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias combinationMatchProducesList = (LC, DC, RC) -> [Module] + public typealias CombinationMatchProducesList = @Sendable (LC, DC, RC) -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: combinationMatchProducesList + public let produceClosure: CombinationMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingTypes: (LC.Type, DC.Type, RC.Type) @@ -47,7 +47,7 @@ public struct RewriteRuleLeftDirectRight: Rule where LC: Module, DC: /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(leftType: LC.Type, directType: DC.Type, rightType: RC.Type, where _: ((LC, DC, RC) -> Bool)?, - produces produceClosure: @escaping combinationMatchProducesList) + produces produceClosure: @escaping CombinationMatchProducesList) { matchingTypes = (leftType, directType, rightType) self.produceClosure = produceClosure diff --git a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRightDefines.swift b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRightDefines.swift index 5878b6b2..5f4730b6 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRightDefines.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRightDefines.swift @@ -27,18 +27,18 @@ import Foundation /// - ``produceClosure`` /// - ``combinationMatchProducesList`` /// -public struct RewriteRuleLeftDirectRightDefines: Rule where LC: Module, DC: Module, RC: Module { +public struct RewriteRuleLeftDirectRightDefines: Rule where LC: Module, DC: Module, RC: Module, PType: Sendable { /// The set of parameters provided by the L-system for rule evaluation and production. - var parameters: ParametersWrapper + let parameters: PType /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((LC, DC, RC, PType) -> Bool)? - + public let parametricEval: Eval? + public typealias Eval = @Sendable (LC, DC, RC, PType) -> Bool /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias combinationMatchProducesList = (LC, DC, RC, PType) -> [Module] + public typealias CombinationMatchProducesList = @Sendable (LC, DC, RC, PType) async -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: combinationMatchProducesList + public let produceClosure: CombinationMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingTypes: (LC.Type, DC.Type, RC.Type) @@ -49,13 +49,14 @@ public struct RewriteRuleLeftDirectRightDefines: Rule where L /// - prng: An optional psuedo-random number generator to use for stochastic rule productions. /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(leftType: LC.Type, directType: DC.Type, rightType: RC.Type, - parameters: ParametersWrapper, - where _: ((LC, DC, RC, PType) -> Bool)?, - produces produceClosure: @escaping combinationMatchProducesList) + parameters: PType, + where eval: Eval?, + produces produceClosure: @escaping CombinationMatchProducesList) { matchingTypes = (leftType, directType, rightType) self.parameters = parameters self.produceClosure = produceClosure + parametricEval = eval } /// Determines if a rule should be evaluated while processing the individual atoms of an L-system state sequence. @@ -80,7 +81,7 @@ public struct RewriteRuleLeftDirectRightDefines: Rule where L let directInstance = matchSet.directInstance as? DC, let rightInstance = matchSet.rightInstance as? RC else { return false } - return additionalEval(leftInstance, directInstance, rightInstance, parameters.unwrap()) + return additionalEval(leftInstance, directInstance, rightInstance, parameters) } return true @@ -89,14 +90,14 @@ public struct RewriteRuleLeftDirectRightDefines: Rule where L /// Invokes the rule's produce closure with the modules provided. /// - Parameter matchSet: The module instances to pass to the produce closure. /// - Returns: A sequence of modules that the produce closure returns. - public func produce(_ matchSet: ModuleSet) -> [Module] { + public func produce(_ matchSet: ModuleSet) async -> [Module] { guard let leftInstance = matchSet.leftInstance as? LC, let directInstance = matchSet.directInstance as? DC, let rightInstance = matchSet.rightInstance as? RC else { return [] } - return produceClosure(leftInstance, directInstance, rightInstance, parameters.unwrap()) + return await produceClosure(leftInstance, directInstance, rightInstance, parameters) } } diff --git a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRightDefinesRNG.swift b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRightDefinesRNG.swift index 62c6b802..9abe2131 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRightDefinesRNG.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRightDefinesRNG.swift @@ -28,21 +28,21 @@ import Foundation /// - ``combinationMatchProducesList`` /// -public struct RewriteRuleLeftDirectRightDefinesRNG: Rule where LC: Module, DC: Module, RC: Module, PRNG: SeededRandomNumberGenerator { +public struct RewriteRuleLeftDirectRightDefinesRNG: Rule where LC: Module, DC: Module, RC: Module, PRNG: SeededRandomNumberGenerator, PType: Sendable { /// The set of parameters provided by the L-system for rule evaluation and production. - var parameters: ParametersWrapper + let parameters: PType /// A psuedo-random number generator to use for stochastic rule productions. var prng: RNGWrapper /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((LC, DC, RC, PType) -> Bool)? - + public let parametricEval: Eval? + public typealias Eval = @Sendable (LC, DC, RC, PType) -> Bool /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias combinationMatchProducesList = (LC, DC, RC, PType, RNGWrapper) -> [Module] + public typealias CombinationMatchProducesList = @Sendable (LC, DC, RC, PType, RNGWrapper) async -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: combinationMatchProducesList + public let produceClosure: CombinationMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingTypes: (LC.Type, DC.Type, RC.Type) @@ -53,15 +53,16 @@ public struct RewriteRuleLeftDirectRightDefinesRNG: Rul /// - prng: An optional psuedo-random number generator to use for stochastic rule productions. /// - singleModuleProduce: A closure that produces an array of L-system state elements to use in place of the current element. public init(leftType: LC.Type, directType: DC.Type, rightType: RC.Type, - parameters: ParametersWrapper, + parameters: PType, prng: RNGWrapper, - where _: ((LC, DC, RC, PType) -> Bool)?, - produces produceClosure: @escaping combinationMatchProducesList) + where eval: Eval?, + produces produceClosure: @escaping CombinationMatchProducesList) { matchingTypes = (leftType, directType, rightType) self.parameters = parameters self.prng = prng self.produceClosure = produceClosure + parametricEval = eval } /// Determines if a rule should be evaluated while processing the individual atoms of an L-system state sequence. @@ -86,7 +87,7 @@ public struct RewriteRuleLeftDirectRightDefinesRNG: Rul let directInstance = matchSet.directInstance as? DC, let rightInstance = matchSet.rightInstance as? RC else { return false } - return additionalEval(leftInstance, directInstance, rightInstance, parameters.unwrap()) + return additionalEval(leftInstance, directInstance, rightInstance, parameters) } return true @@ -95,14 +96,14 @@ public struct RewriteRuleLeftDirectRightDefinesRNG: Rul /// Invokes the rule's produce closure with the modules provided. /// - Parameter matchSet: The module instances to pass to the produce closure. /// - Returns: A sequence of modules that the produce closure returns. - public func produce(_ matchSet: ModuleSet) -> [Module] { + public func produce(_ matchSet: ModuleSet) async -> [Module] { guard let leftInstance = matchSet.leftInstance as? LC, let directInstance = matchSet.directInstance as? DC, let rightInstance = matchSet.rightInstance as? RC else { return [] } - return produceClosure(leftInstance, directInstance, rightInstance, parameters.unwrap(), prng) + return await produceClosure(leftInstance, directInstance, rightInstance, parameters, prng) } } diff --git a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRightRNG.swift b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRightRNG.swift index 24aefd12..f41a1c79 100644 --- a/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRightRNG.swift +++ b/Sources/Lindenmayer/Rules/RewriteRuleLeftDirectRightRNG.swift @@ -32,13 +32,13 @@ public struct RewriteRuleLeftDirectRightRNG: Rule where LC: Mo var prng: RNGWrapper /// An optional closure that provides the module to which it is being compared that returns whether the rule should be applied. - public var parametricEval: ((LC, DC, RC) -> Bool)? + public var parametricEval: (@Sendable (LC, DC, RC) -> Bool)? /// The signature of the produce closure that provides a module and expects a sequence of modules. - public typealias combinationMatchProducesList = (LC, DC, RC, RNGWrapper) -> [Module] + public typealias CombinationMatchProducesList = @Sendable (LC, DC, RC, RNGWrapper) async -> [Module] /// The closure that provides the L-system state for the current, previous, and next nodes in the state sequence and expects an array of state elements with which to replace the current state. - public let produceClosure: combinationMatchProducesList + public let produceClosure: CombinationMatchProducesList /// The L-system uses the types of these modules to determine is this rule should be applied and re-write the current state. public let matchingTypes: (LC.Type, DC.Type, RC.Type) @@ -51,7 +51,7 @@ public struct RewriteRuleLeftDirectRightRNG: Rule where LC: Mo public init(leftType: LC.Type, directType: DC.Type, rightType: RC.Type, prng: RNGWrapper, where _: ((LC, DC, RC) -> Bool)?, - produces produceClosure: @escaping combinationMatchProducesList) + produces produceClosure: @escaping CombinationMatchProducesList) { matchingTypes = (leftType, directType, rightType) self.prng = prng @@ -89,14 +89,14 @@ public struct RewriteRuleLeftDirectRightRNG: Rule where LC: Mo /// Invokes the rule's produce closure with the modules provided. /// - Parameter matchSet: The module instances to pass to the produce closure. /// - Returns: A sequence of modules that the produce closure returns. - public func produce(_ matchSet: ModuleSet) -> [Module] { + public func produce(_ matchSet: ModuleSet) async -> [Module] { guard let leftInstance = matchSet.leftInstance as? LC, let directInstance = matchSet.directInstance as? DC, let rightInstance = matchSet.rightInstance as? RC else { return [] } - return produceClosure(leftInstance, directInstance, rightInstance, prng) + return await produceClosure(leftInstance, directInstance, rightInstance, prng) } } diff --git a/Sources/Lindenmayer/Rules/Rule.swift b/Sources/Lindenmayer/Rules/Rule.swift index d36130cf..6791c42d 100644 --- a/Sources/Lindenmayer/Rules/Rule.swift +++ b/Sources/Lindenmayer/Rules/Rule.swift @@ -26,5 +26,5 @@ public protocol Rule: Sendable { /// Returns a sequence of modules based on the existing module, and potentially it's contextual position with the module to the right and left. /// - Returns: The sequence of modules that replaces the current module during evolution. - func produce(_ matchSet: ModuleSet) -> [Module] + func produce(_ matchSet: ModuleSet) async -> [Module] } diff --git a/Sources/LindenmayerViews/Dynamic2DLSystemViews.swift b/Sources/LindenmayerViews/Dynamic2DLSystemViews.swift index 901691c6..32503947 100644 --- a/Sources/LindenmayerViews/Dynamic2DLSystemViews.swift +++ b/Sources/LindenmayerViews/Dynamic2DLSystemViews.swift @@ -10,6 +10,7 @@ import SwiftUI /// A view that allows you to choose from a collection of the built-in 2D L-systems and display the 2D representation of the L-system at the number of iterations that you select in the view. @available(macOS 12.0, iOS 15.0, *) +@MainActor public struct Dynamic2DLSystemViews: View { enum TwoDExamples: String, CaseIterable, Identifiable { case algae @@ -82,7 +83,8 @@ public struct Dynamic2DLSystemViews: View { #endif } .padding() - Lsystem2DView(system: selectedSystem.lsystem.evolved(iterations: Int(evolutions)), + Lsystem2DView(system: selectedSystem.lsystem, + iterations: Int(evolutions), displayMetrics: false) .padding() } diff --git a/Sources/LindenmayerViews/Examples/Monopodial4Examples.swift b/Sources/LindenmayerViews/Examples/Monopodial4Examples.swift index 9603192d..b4db1f0b 100644 --- a/Sources/LindenmayerViews/Examples/Monopodial4Examples.swift +++ b/Sources/LindenmayerViews/Examples/Monopodial4Examples.swift @@ -13,10 +13,10 @@ import SwiftUI /// /// The set of trees match the examples of figure 2.6 in [The Algorithmic Beauty of Plants](http://algorithmicbotany.org/papers/abop/abop.pdf) on page 56. public struct Monopodial4Examples: View { - let system1: LindenmayerSystem - let system2: LindenmayerSystem - let system3: LindenmayerSystem - let system4: LindenmayerSystem + @State var system1: LindenmayerSystem + @State var system2: LindenmayerSystem + @State var system3: LindenmayerSystem + @State var system4: LindenmayerSystem let renderer = SceneKitRenderer() public var body: some View { VStack { @@ -28,22 +28,23 @@ public struct Monopodial4Examples: View { Lsystem3DView(system: system3) Lsystem3DView(system: system4) } + }.task { + system1 = await system1.evolved(iterations: 10) + system2 = await system2.evolved(iterations: 10) + system3 = await system3.evolved(iterations: 10) + system4 = await system4.evolved(iterations: 10) } } public init() { system1 = Examples3D.monopodialTree .setParameters(params: Examples3D.figure2_6A) - .evolved(iterations: 10) system2 = Examples3D.monopodialTree .setParameters(params: Examples3D.figure2_6B) - .evolved(iterations: 10) system3 = Examples3D.monopodialTree .setParameters(params: Examples3D.figure2_6C) - .evolved(iterations: 10) system4 = Examples3D.monopodialTree .setParameters(params: Examples3D.figure2_6D) - .evolved(iterations: 10) } } diff --git a/Sources/LindenmayerViews/Examples/Sympodial4Examples.swift b/Sources/LindenmayerViews/Examples/Sympodial4Examples.swift index a3ff1b90..92807f72 100644 --- a/Sources/LindenmayerViews/Examples/Sympodial4Examples.swift +++ b/Sources/LindenmayerViews/Examples/Sympodial4Examples.swift @@ -13,10 +13,10 @@ import SwiftUI /// /// The set of trees match the example in figure 2.7 of [The Algorithmic Beauty of Plants](http://algorithmicbotany.org/papers/abop/abop.pdf) on page 59. public struct Sympodial4Examples: View { - let system1: LindenmayerSystem - let system2: LindenmayerSystem - let system3: LindenmayerSystem - let system4: LindenmayerSystem + @State var system1: LindenmayerSystem + @State var system2: LindenmayerSystem + @State var system3: LindenmayerSystem + @State var system4: LindenmayerSystem let renderer = SceneKitRenderer() public var body: some View { VStack { @@ -28,22 +28,23 @@ public struct Sympodial4Examples: View { Lsystem3DView(system: system3) Lsystem3DView(system: system4) } + }.task { + system1 = await system1.evolved(iterations: 10) + system2 = await system2.evolved(iterations: 10) + system3 = await system3.evolved(iterations: 10) + system4 = await system4.evolved(iterations: 10) } } public init() { system1 = Examples3D.sympodialTree .setParameters(params: Examples3D.figure2_7A) - .evolved(iterations: 10) system2 = Examples3D.sympodialTree .setParameters(params: Examples3D.figure2_7B) - .evolved(iterations: 10) system3 = Examples3D.sympodialTree .setParameters(params: Examples3D.figure2_7C) - .evolved(iterations: 10) system4 = Examples3D.sympodialTree .setParameters(params: Examples3D.figure2_7D) - .evolved(iterations: 10) } } diff --git a/Sources/LindenmayerViews/LSystem3DControlView.swift b/Sources/LindenmayerViews/LSystem3DControlView.swift index dc26d937..51c11b0b 100644 --- a/Sources/LindenmayerViews/LSystem3DControlView.swift +++ b/Sources/LindenmayerViews/LSystem3DControlView.swift @@ -15,6 +15,7 @@ import SwiftUI /// The controls within the view allow you to select the number of iterations for the L-system. /// Within the resulting L-system's state, you can select each state of the L-system, which points the 3D camera at that node and highlights it. /// The view is intended to provide a visualization with sufficient detail about the state and its representation for debugging how an L-system is represented in 3D. +@MainActor public struct LSystem3DControlView: View { var model: LSystem3DModel @State private var iterations = 1 diff --git a/Sources/LindenmayerViews/LSystem3DModel.swift b/Sources/LindenmayerViews/LSystem3DModel.swift index c5deea74..bff50790 100644 --- a/Sources/LindenmayerViews/LSystem3DModel.swift +++ b/Sources/LindenmayerViews/LSystem3DModel.swift @@ -5,7 +5,7 @@ // Created by Joseph Heck on 1/8/22. // -import Combine +@preconcurrency import Combine import Foundation import Lindenmayer import SceneKit @@ -16,6 +16,7 @@ import SwiftUI /// /// The module manages the number of evolutions of an L-system, and provides updated 3D SceneKit scenes as you change the number of evolutions. /// The model emits `ObservableObject` change notifications when the number of iterations is changed. +@MainActor public class LSystem3DModel: ObservableObject { @Published public var system: LindenmayerSystem let renderer = SceneKitRenderer() @@ -24,7 +25,7 @@ public class LSystem3DModel: ObservableObject { var _scene: SCNScene var _transformSequence: [matrix_float4x4] - public var objectWillChange = Combine.ObservableObjectPublisher() + public let objectWillChange: ObservableObjectPublisher public var scene: SCNScene { _scene @@ -34,6 +35,17 @@ public class LSystem3DModel: ObservableObject { _transformSequence } + func evolveBy(iterations: Int) async { + system = await _baseSystem.evolved(iterations: _iterations) + objectWillChange.send() + (_scene, _transformSequence) = renderer.generateScene(lsystem: system) + let headingIndicator = DebugNodes.headingIndicator() + headingIndicator.opacity = 0 + let bigger = SceneKitRenderer.scalingTransform(x: 2.5, y: 2.5, z: 2.5) + headingIndicator.simdTransform = matrix_multiply(headingIndicator.simdTransform, bigger) + _scene.rootNode.addChildNode(headingIndicator) + } + var _iterations = 1 public var iterations: Int { get { @@ -42,14 +54,9 @@ public class LSystem3DModel: ObservableObject { set { precondition(newValue > 0 && newValue < 20) _iterations = newValue - objectWillChange.send() - system = _baseSystem.evolved(iterations: _iterations) - (_scene, _transformSequence) = renderer.generateScene(lsystem: system) - let headingIndicator = DebugNodes.headingIndicator() - headingIndicator.opacity = 0 - let bigger = SceneKitRenderer.scalingTransform(x: 2.5, y: 2.5, z: 2.5) - headingIndicator.simdTransform = matrix_multiply(headingIndicator.simdTransform, bigger) - _scene.rootNode.addChildNode(headingIndicator) + Task { + await self.evolveBy(iterations: _iterations) + } } } @@ -57,6 +64,7 @@ public class LSystem3DModel: ObservableObject { /// - Parameter system: The L-System to expose and control with the model. public init(system: LindenmayerSystem) { self.system = system + objectWillChange = ObservableObjectPublisher() (_scene, _transformSequence) = renderer.generateScene(lsystem: _baseSystem) let headingIndicator = DebugNodes.headingIndicator() _scene.rootNode.addChildNode(headingIndicator) @@ -65,6 +73,7 @@ public class LSystem3DModel: ObservableObject { /// Creates a default L-System model using the sympodial tree example. public init() { system = _baseSystem + objectWillChange = ObservableObjectPublisher() (_scene, _transformSequence) = renderer.generateScene(lsystem: _baseSystem) let headingIndicator = DebugNodes.headingIndicator() _scene.rootNode.addChildNode(headingIndicator) diff --git a/Sources/LindenmayerViews/Lsystem2DView.swift b/Sources/LindenmayerViews/Lsystem2DView.swift index 1c472703..7a5c34a3 100644 --- a/Sources/LindenmayerViews/Lsystem2DView.swift +++ b/Sources/LindenmayerViews/Lsystem2DView.swift @@ -10,9 +10,11 @@ import SwiftUI /// A view that provides a 2D rendering of the L-system provide, and optionally metrics associated with the L-system. @available(macOS 12.0, iOS 15.0, *) +@MainActor public struct Lsystem2DView: View { + let iterations: Int let displayMetrics: Bool - let system: LindenmayerSystem + @State var system: LindenmayerSystem let renderer = GraphicsContextRenderer() public var body: some View { VStack { @@ -22,11 +24,14 @@ public struct Lsystem2DView: View { Canvas { context, size in renderer.draw(system, into: &context, ofSize: size) } + }.task { + system = await system.evolved(iterations: iterations) } } - public init(system: LindenmayerSystem, displayMetrics: Bool = false) { + public init(system: LindenmayerSystem, iterations: Int, displayMetrics: Bool = false) { self.system = system + self.iterations = iterations self.displayMetrics = displayMetrics } } @@ -34,7 +39,7 @@ public struct Lsystem2DView: View { @available(macOS 12.0, iOS 15.0, *) struct Lsystem2DView_Previews: PreviewProvider { static var previews: some View { - Lsystem2DView(system: Examples2D.barnsleyFern.evolved(iterations: 4), + Lsystem2DView(system: Examples2D.barnsleyFern, iterations: 4, displayMetrics: true) } } diff --git a/Sources/LindenmayerViews/Lsystem3DView.swift b/Sources/LindenmayerViews/Lsystem3DView.swift index b0a77371..7bf764e6 100644 --- a/Sources/LindenmayerViews/Lsystem3DView.swift +++ b/Sources/LindenmayerViews/Lsystem3DView.swift @@ -10,9 +10,10 @@ import SceneKit import SwiftUI /// A view that provides a 3D rendering of the L-system provide, and optionally metrics associated with the L-system. +@MainActor public struct Lsystem3DView: View { let displayMetrics: Bool - let system: LindenmayerSystem + @State var system: LindenmayerSystem func generateScene() -> SCNScene { let x = SceneKitRenderer() return x.generateScene(lsystem: system).0 @@ -46,6 +47,9 @@ public struct Lsystem3DView: View { // scnView.showsStatistics = true // scnView.backgroundColor = .white } + .task { + system = await system.evolved(iterations: 4) + } } public init(system: LindenmayerSystem, displayMetrics: Bool = false) { @@ -56,7 +60,7 @@ public struct Lsystem3DView: View { struct Lsystem3DView_Previews: PreviewProvider { static var previews: some View { - Lsystem3DView(system: Examples3D.algae3D.evolved(iterations: 4), + Lsystem3DView(system: Examples3D.algae3D, displayMetrics: true) } } diff --git a/Sources/LindenmayerViews/ViewComponents/HorizontalLSystemStateView.swift b/Sources/LindenmayerViews/ViewComponents/HorizontalLSystemStateView.swift index 910a970b..d1b1fda4 100644 --- a/Sources/LindenmayerViews/ViewComponents/HorizontalLSystemStateView.swift +++ b/Sources/LindenmayerViews/ViewComponents/HorizontalLSystemStateView.swift @@ -31,9 +31,14 @@ public struct HorizontalLSystemStateView: View { @available(macOS 12.0, iOS 15.0, *) struct HorizontalLSystemStateView_Previews: PreviewProvider { static var previews: some View { - let system = Examples3D.monopodialTree.evolved(iterations: 4) - ForEach(SummarySizes.allCases, id: \.self) { sizeChoice in - HorizontalLSystemStateView(size: sizeChoice, system: system) + @State var system = Examples3D.monopodialTree + Group { + ForEach(SummarySizes.allCases, id: \.self) { sizeChoice in + HorizontalLSystemStateView(size: sizeChoice, system: system) + } + } + .task { + system = await system.evolved(iterations: 4) } } } diff --git a/Sources/LindenmayerViews/ViewComponents/LSystemMetrics.swift b/Sources/LindenmayerViews/ViewComponents/LSystemMetrics.swift index 9c5977f9..c5b94f98 100644 --- a/Sources/LindenmayerViews/ViewComponents/LSystemMetrics.swift +++ b/Sources/LindenmayerViews/ViewComponents/LSystemMetrics.swift @@ -10,7 +10,7 @@ import SwiftUI /// A view that provides the size of the state of an L-system and a textual representation of that state. public struct LSystemMetrics: View { - let system: LindenmayerSystem + @State var system: LindenmayerSystem public var body: some View { VStack { Text("State size: \(system.state.count)") @@ -18,6 +18,8 @@ public struct LSystemMetrics: View { .font(.caption) .lineLimit(3) .padding(.horizontal) + }.task { + system = await system.evolved(iterations: 4) } } @@ -28,6 +30,6 @@ public struct LSystemMetrics: View { struct LSystemMetrics_Previews: PreviewProvider { static var previews: some View { - LSystemMetrics(system: Examples3D.monopodialTree.evolved(iterations: 4)) + LSystemMetrics(system: Examples3D.monopodialTree) } } diff --git a/Sources/LindenmayerViews/ViewComponents/ModuleDetailView.swift b/Sources/LindenmayerViews/ViewComponents/ModuleDetailView.swift index 4a8cc0fe..3c7aeb86 100644 --- a/Sources/LindenmayerViews/ViewComponents/ModuleDetailView.swift +++ b/Sources/LindenmayerViews/ViewComponents/ModuleDetailView.swift @@ -42,7 +42,7 @@ public struct ModuleDetailView: View { struct ModuleDetailView_Previews: PreviewProvider { static func provideModule() -> DebugModule { - Examples3D.monopodialTree.evolved(iterations: 4).state(at: 3) + Examples3D.monopodialTree.state(at: 3) } static var previews: some View { diff --git a/Sources/LindenmayerViews/ViewComponents/ModuleSummaryView.swift b/Sources/LindenmayerViews/ViewComponents/ModuleSummaryView.swift index 4a089bfb..f5afdc85 100644 --- a/Sources/LindenmayerViews/ViewComponents/ModuleSummaryView.swift +++ b/Sources/LindenmayerViews/ViewComponents/ModuleSummaryView.swift @@ -56,18 +56,16 @@ public struct ModuleSummaryView: View { @available(macOS 12.0, iOS 15.0, *) struct ModuleSummaryView_Previews: PreviewProvider { - static func provideModule() -> DebugModule { - Examples3D.monopodialTree.evolved(iterations: 4).state(at: 13) - } - static var previews: some View { - let system = Examples3D.monopodialTree.evolved(iterations: 4) + @State var system = Examples3D.monopodialTree ForEach(SummarySizes.allCases, id: \.self) { sizeChoice in HStack(alignment: .top, spacing: 1) { ForEach(system.identifiableModules()) { ModuleSummaryView(size: sizeChoice, module: $0) } } + }.task { + system = await system.evolved(iterations: 4) } } } diff --git a/Sources/LindenmayerViews/ViewComponents/StateSelectorView.swift b/Sources/LindenmayerViews/ViewComponents/StateSelectorView.swift index 5d41bb7a..edf44d47 100644 --- a/Sources/LindenmayerViews/ViewComponents/StateSelectorView.swift +++ b/Sources/LindenmayerViews/ViewComponents/StateSelectorView.swift @@ -6,12 +6,13 @@ // import Lindenmayer -import SwiftUI +@preconcurrency import SwiftUI /// A view that provides a visual representation of the states of an L-system and allows the person viewing it to select an index position from that L-system's state. @available(macOS 12.0, iOS 15.0, *) +@MainActor public struct StateSelectorView: View { - let system: LindenmayerSystem + @State var system: LindenmayerSystem let _withDetailView: Bool // state for the related views that show stuff @Binding var indexPosition: Int @@ -108,10 +109,14 @@ public struct StateSelectorView: View { forwardTimer?.invalidate() // or fastforward has started to start the timer reverseTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { _ in - if sliderPosition >= 1.0 { - sliderPosition -= 1 - indexPosition -= 1 - proxy.scrollTo(indexPosition) + Task { + await MainActor.run { + if sliderPosition >= 1.0 { + sliderPosition -= 1 + indexPosition -= 1 + proxy.scrollTo(indexPosition) + } + } } }) }) @@ -162,10 +167,14 @@ public struct StateSelectorView: View { reverseTimer?.invalidate() // or fastforward has started to start the timer forwardTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { _ in - if sliderPosition < Double(system.state.count - 1) { - sliderPosition += 1 - indexPosition += 1 - proxy.scrollTo(indexPosition) + Task { + await MainActor.run { + if sliderPosition < Double(system.state.count - 1) { + sliderPosition += 1 + indexPosition += 1 + proxy.scrollTo(indexPosition) + } + } } }) }) @@ -189,7 +198,12 @@ public struct StateSelectorView: View { @available(macOS 12.0, iOS 15.0, *) struct StateSelectorView_Previews: PreviewProvider { static var previews: some View { - StateSelectorView(system: Examples3D.monopodialTree.evolved(iterations: 4), position: .constant(13)) - StateSelectorView(system: Examples3D.monopodialTree.evolved(iterations: 4), position: .constant(13), withDetailView: true) + @State var system = Examples3D.monopodialTree + Group { + StateSelectorView(system: system, position: .constant(13)) + StateSelectorView(system: system, position: .constant(13), withDetailView: true) + }.task { + system = await system.evolved(iterations: 4) + } } } diff --git a/Sources/LindenmayerViews/ViewComponents/WindowedSmallModuleView.swift b/Sources/LindenmayerViews/ViewComponents/WindowedSmallModuleView.swift index a00ac523..15d81b31 100644 --- a/Sources/LindenmayerViews/ViewComponents/WindowedSmallModuleView.swift +++ b/Sources/LindenmayerViews/ViewComponents/WindowedSmallModuleView.swift @@ -14,7 +14,7 @@ import SwiftUI @available(macOS 12.0, iOS 15.0, *) public struct WindowedSmallModuleView: View { let size: SummarySizes - let system: LindenmayerSystem + @State var system: LindenmayerSystem let position: Int let windowSize: Int @@ -94,6 +94,8 @@ public struct WindowedSmallModuleView: View { .scaleEffect(x: 0.8, y: 0.8) } } + }.task { + system = await system.evolved(iterations: 4) } } @@ -119,12 +121,12 @@ struct WindowedSmallModuleView_Previews: PreviewProvider { ForEach(SummarySizes.allCases, id: \.self) { sizeChoice in WindowedSmallModuleView( size: sizeChoice, - system: Examples3D.monopodialTree.evolved(iterations: 4), + system: Examples3D.monopodialTree, position: 13 ) } ForEach([0, 3, 5, 7, 11], id: \.self) { windowSizeChoice in - WindowedSmallModuleView(size: .medium, system: Examples3D.monopodialTree.evolved(iterations: 4), position: 13, windowSize: windowSizeChoice) + WindowedSmallModuleView(size: .medium, system: Examples3D.monopodialTree, position: 13, windowSize: windowSizeChoice) } } } diff --git a/Tests/LindenmayerTests/GraphicsContextRendererTests.swift b/Tests/LindenmayerTests/GraphicsContextRendererTests.swift index ea1b64ed..552f47d0 100644 --- a/Tests/LindenmayerTests/GraphicsContextRendererTests.swift +++ b/Tests/LindenmayerTests/GraphicsContextRendererTests.swift @@ -2,9 +2,9 @@ import Lindenmayer import XCTest final class GraphicsContextRendererTests: XCTestCase { - func testLSystem_boundingRectCalc() throws { + func testLSystem_boundingRectCalc() async throws { let tree = Examples2D.kochCurve - let evo1 = tree.evolved(iterations: 3) + let evo1 = await tree.evolved(iterations: 3) let path: CGRect = GraphicsContextRenderer().calcBoundingRect(system: evo1) // print(path) // print("Size: \(path.size) -> height: \(path.size.height), width: \(path.size.width)") diff --git a/Tests/LindenmayerTests/LSystemTests.swift b/Tests/LindenmayerTests/LSystemTests.swift index 9a706346..ebbecf4b 100644 --- a/Tests/LindenmayerTests/LSystemTests.swift +++ b/Tests/LindenmayerTests/LSystemTests.swift @@ -2,7 +2,7 @@ import XCTest final class LSystemTests: XCTestCase { - func testLSystemDefault() throws { + func testLSystemDefault() async throws { let x = RandomContextualLSystem(axiom: [Examples2D.Internode()], state: nil, newStateIndicators: nil, prng: RNGWrapper(Xoshiro(seed: 0))) XCTAssertNotNil(x) @@ -16,20 +16,20 @@ final class LSystemTests: XCTestCase { XCTAssertEqual(result[0].render2D[0].name, RenderCommand.Draw(length: 10).name) XCTAssertEqual(result[0].render3D.name, RenderCommand.Ignore().name) - let updated = x.evolve() + let updated = await x.evolve() XCTAssertEqual(updated.state.count, 1) XCTAssertEqual(updated.state.count, updated.newStateIndicators.count) let downcast = updated.state[0] as! Examples2D.Internode XCTAssertEqual(downcast.description, "I") } - func testAlgaeLSystem_evolve1() throws { + func testAlgaeLSystem_evolve1() async throws { let algae = Examples2D.algae XCTAssertNotNil(algae) XCTAssertEqual(algae.state.count, 1) XCTAssertEqual(algae.state.map(\.description).joined(), "A") - let iter1 = algae.evolve() // debugPrint: true + let iter1 = await algae.evolve() // debugPrint: true XCTAssertEqual(iter1.state.count, 2) XCTAssertEqual(iter1.state.count, iter1.newStateIndicators.count) @@ -40,42 +40,42 @@ final class LSystemTests: XCTestCase { XCTAssertEqual(resultSequence, "AB") } - func testAlgaeLSystem_evolve2() throws { + func testAlgaeLSystem_evolve2() async throws { var resultSequence = "" let algae = Examples2D.algae - let iter2 = algae.evolve() + let iter2 = await algae.evolve() resultSequence = iter2.state.map(\.description).joined() XCTAssertEqual(resultSequence, "AB") - let iter3 = iter2.evolve() // debugPrint: true + let iter3 = await iter2.evolve() // debugPrint: true resultSequence = iter3.state.map(\.description).joined() XCTAssertEqual(resultSequence, "ABA") XCTAssertEqual(iter3.state.count, iter3.newStateIndicators.count) } - func testAlgaeLSystem_evolve3() throws { + func testAlgaeLSystem_evolve3() async throws { var resultSequence = "" let algae = Examples2D.algae - let evolution = algae.evolved(iterations: 3) + let evolution = await algae.evolved(iterations: 3) resultSequence = evolution.state.map(\.description).joined() XCTAssertEqual(resultSequence, "ABAAB") - let evolution2 = evolution.evolve() + let evolution2 = await evolution.evolve() resultSequence = evolution2.state.map(\.description).joined() XCTAssertEqual(resultSequence, "ABAABABA") XCTAssertEqual(evolution2.state.count, evolution2.newStateIndicators.count) } - func testFractalTree_evolve2() throws { + func testFractalTree_evolve2() async throws { let tree = Examples2D.fractalTree - let evo1 = tree.evolve() + let evo1 = await tree.evolve() XCTAssertEqual(evo1.state.map(\.description).joined(), "I[+L]-L") XCTAssertEqual(evo1.newStateIndicators, [true, true, true, true, true, true, true]) - let evo2 = evo1.evolve() + let evo2 = await evo1.evolve() XCTAssertEqual(evo2.state.map(\.description).joined(), "II[+I[+L]-L]-I[+L]-L") } - func testLSystem_kochCurve() throws { + func testLSystem_kochCurve() async throws { let tree = Examples2D.kochCurve - let evo1 = tree.evolved(iterations: 3) + let evo1 = await tree.evolved(iterations: 3) XCTAssertEqual(evo1.state.map(\.description).joined(), "F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F+F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F-F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F-F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F+F+F-F-F+F+F+F-F-F+F-F+F-F-F+F-F+F-F-F+F+F+F-F-F+F") print(evo1.newStateIndicators) diff --git a/Tests/LindenmayerTests/PRNGWrapperTests.swift b/Tests/LindenmayerTests/PRNGWrapperTests.swift index afe351c1..14859ab4 100644 --- a/Tests/LindenmayerTests/PRNGWrapperTests.swift +++ b/Tests/LindenmayerTests/PRNGWrapperTests.swift @@ -53,46 +53,64 @@ final class PRNGWrapperTests: XCTestCase { XCTAssertEqual(firstResults, secondResults) } - func testCheckingRNGReferenceType() throws { + func testCheckingRNGReferenceType() async throws { // requires `@testable import Lindenmayer` to get to the DetailedExamples struct let start = Examples3D.randomBush - XCTAssertEqual(start.prng.seed, 42) - XCTAssertEqual(start.prng._invokeCount, 0) + var seedValue = await start.prng.seed + var _invokeCount = await start.prng._invokeCount + XCTAssertEqual(seedValue, 42) + XCTAssertEqual(_invokeCount, 0) - let oneEv = start.evolve() - XCTAssertEqual(oneEv.prng.seed, 42) - XCTAssertEqual(oneEv.prng._invokeCount, 2) + let oneEv = await start.evolve() + seedValue = await start.prng.seed + _invokeCount = await start.prng._invokeCount + XCTAssertEqual(seedValue, 42) + XCTAssertEqual(_invokeCount, 2) // print(oneEv.prng.position) let sideTest = RNGWrapper(Xoshiro(seed: 42)) - _ = sideTest.p() - _ = sideTest.p() - XCTAssertEqual(sideTest._invokeCount, 2) - XCTAssertEqual(sideTest.position, oneEv.prng.position) - - let twoEv = oneEv.evolve() + _ = await sideTest.p() + _ = await sideTest.p() + _invokeCount = await sideTest._invokeCount + let sideTestPosition = await sideTest.position + let oneEvPosition = await sideTest.position + XCTAssertEqual(_invokeCount, 2) + XCTAssertEqual(sideTestPosition, oneEvPosition) + + let twoEv = await oneEv.evolve() // Even though evolve is returning a new LSystem, the underlying reference to the RNG should be the same - so it // continues to move forward as new evolutions are invoked. - XCTAssertEqual(twoEv.prng._invokeCount, 4) - start.prng.resetRNG(seed: start.prng.seed) + _invokeCount = await twoEv.prng._invokeCount + XCTAssertEqual(_invokeCount, 4) + await start.prng.resetRNG(seed: start.prng.seed) + _invokeCount = await start.prng._invokeCount + XCTAssertEqual(_invokeCount, 0) } - func testResettingPRNG() throws { + func testResettingPRNG() async throws { // requires `@testable import Lindenmayer` to get to the DetailedExamples struct let start = Examples3D.randomBush - XCTAssertEqual(start.prng.seed, 42) - XCTAssertEqual(start.prng._invokeCount, 0) + var seed = await start.prng.seed + var _invokeCount = await start.prng._invokeCount + XCTAssertEqual(seed, 42) + XCTAssertEqual(_invokeCount, 0) + + let oneEv = await start.evolve() - let oneEv = start.evolve() + seed = await oneEv.prng.seed + _invokeCount = await oneEv.prng._invokeCount - XCTAssertEqual(oneEv.prng.seed, 42) - XCTAssertEqual(oneEv.prng._invokeCount, 2) + XCTAssertEqual(seed, 42) + XCTAssertEqual(_invokeCount, 2) - start.prng.resetRNG(seed: start.prng.seed) - XCTAssertEqual(oneEv.prng.seed, 42) - XCTAssertEqual(oneEv.prng.position, 0) - XCTAssertEqual(oneEv.prng._invokeCount, 0) + await start.prng.resetRNG(seed: start.prng.seed) + let position = await oneEv.prng.position + seed = await oneEv.prng.seed + _invokeCount = await oneEv.prng._invokeCount + XCTAssertEqual(seed, 42) + XCTAssertEqual(position, 0) + XCTAssertEqual(_invokeCount, 0) } } diff --git a/Tests/LindenmayerTests/PWrapperTests.swift b/Tests/LindenmayerTests/PWrapperTests.swift deleted file mode 100644 index 1faaa9f6..00000000 --- a/Tests/LindenmayerTests/PWrapperTests.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// PWrapperTests.swift -// -// -// Created by Joseph Heck on 1/4/22. -// - -@testable import Lindenmayer -import XCTest - -final class PWrapperTests: XCTestCase { - func testInitalParameter() throws { - struct P: Equatable { - let value: Int - } - let initialP = P(value: 10) - - let f = LSystem.create(Examples2D.Internode(), with: Xoshiro(seed: 0), using: initialP) - .rewriteWithParams(directContext: Examples2D.Internode.self) { m, params in - XCTAssertEqual(params.value, 10) - return [m] - } - let next = f.evolve() - XCTAssertEqual(f.parameters.unwrap().value, 10) - XCTAssertNotNil(next) - } - - func testUpdatedParameter() throws { - struct P: Equatable { - let value: Int - } - let initialP = P(value: 10) - - let f = LSystem.create(Examples2D.Internode(), with: Xoshiro(seed: 0), using: initialP) - .rewriteWithParams(directContext: Examples2D.Internode.self) { m, params in - XCTAssertEqual(params.value, 13) - return [m] - } - XCTAssertEqual(f.parameters.unwrap().value, 10) - f.parameters.update(P(value: 13)) - let next = f.evolve() - XCTAssertEqual(f.parameters.unwrap().value, 13) - XCTAssertNotNil(next) - } - - func testCodabling() throws { - let x = JSONEncoder() - let zzz = try x.encode(Examples3D.figure2_6B) - print(String(data: zzz, encoding: .utf8)!) - /* - {"contractionRatioForTrunk":0.9,"widthContraction":0.707,"lateralBranchAngle":45,"trunklength":10,"trunkdiameter":1,"branchAngle":45,"divergence":137.5,"contractionRatioForBranch":0.9} - */ - } -} diff --git a/Tests/LindenmayerTests/ParameterTests.swift b/Tests/LindenmayerTests/ParameterTests.swift new file mode 100644 index 00000000..d1af5e05 --- /dev/null +++ b/Tests/LindenmayerTests/ParameterTests.swift @@ -0,0 +1,36 @@ +// +// ParameterTests.swift +// +// +// Created by Joseph Heck on 1/4/22. +// + +@testable import Lindenmayer +import XCTest + +final class ParameterTests: XCTestCase { + func testInitalParameter() async throws { + struct P: Equatable { + let value: Int + } + let initialP = P(value: 10) + + let f = LSystem.create(Examples2D.Internode(), with: Xoshiro(seed: 0), using: initialP) + .rewriteWithParams(directContext: Examples2D.Internode.self) { m, params in + XCTAssertEqual(params.value, 10) + return [m] + } + let next = await f.evolve() + XCTAssertEqual(f.parameters.value, 10) + XCTAssertNotNil(next) + } + + func testCodabling() throws { + let x = JSONEncoder() + let zzz = try x.encode(Examples3D.figure2_6B) + print(String(data: zzz, encoding: .utf8)!) + /* + {"trunkdiameter":1,"lateralBranchAngle":45,"contractionRatioForBranch":0.9,"divergence":137.5,"contractionRatioForTrunk":0.9,"widthContraction":0.707,"branchAngle":45,"trunklength":10} + */ + } +} diff --git a/Tests/LindenmayerTests/PerformanceTests.swift b/Tests/LindenmayerTests/PerformanceTests.swift index 8cb40884..6dfce642 100644 --- a/Tests/LindenmayerTests/PerformanceTests.swift +++ b/Tests/LindenmayerTests/PerformanceTests.swift @@ -2,28 +2,28 @@ import Lindenmayer import XCTest final class PerformanceTests: XCTestCase { - func X_testMemoryUse() { - measure(metrics: [XCTMemoryMetric()]) { - let tree = Examples2D.barnsleyFern - let evo1 = tree.evolved(iterations: 6) - XCTAssertNotNil(evo1) - } + func X_testMemoryUse() async { +// measure(metrics: [XCTMemoryMetric()]) { + let tree = Examples2D.barnsleyFern + let evo1 = await tree.evolved(iterations: 6) + XCTAssertNotNil(evo1) +// } } - func X_testEvolutionSpeed() { - measure { - // 20.675 seconds - let tree = Examples2D.barnsleyFern - let evo1 = tree.evolved(iterations: 10) - XCTAssertNotNil(evo1) - } + func X_testEvolutionSpeed() async { +// measure async { + // 20.675 seconds + let tree = Examples2D.barnsleyFern + let evo1 = await tree.evolved(iterations: 10) + XCTAssertNotNil(evo1) +// } } - func X_testPerfBoundingRectCalc() { + func X_testPerfBoundingRectCalc() async { let evo1: LindenmayerSystem? // 20.675 seconds let tree = Examples2D.barnsleyFern - evo1 = tree.evolved(iterations: 10) + evo1 = await tree.evolved(iterations: 10) XCTAssertNotNil(evo1) measure { // 9.9 seconds diff --git a/Tests/LindenmayerTests/SnippetsForDocs.swift b/Tests/LindenmayerTests/SnippetsForDocs.swift index eea216fd..6cd65bea 100644 --- a/Tests/LindenmayerTests/SnippetsForDocs.swift +++ b/Tests/LindenmayerTests/SnippetsForDocs.swift @@ -10,8 +10,8 @@ import Lindenmayer import XCTest final class SnippetsForDocs: XCTestCase { - func testDebugModuleSnippets() { - let system = Examples2D.barnsleyFern.evolved(iterations: 4) + func testDebugModuleSnippets() async { + let system = await Examples2D.barnsleyFern.evolved(iterations: 4) let debugModuleInstance = system.state(at: 14) print("ID: \(debugModuleInstance.id), name: \(debugModuleInstance.module.name)") diff --git a/Tests/LindenmayerTests/WhiteboxParametricRuleTests.swift b/Tests/LindenmayerTests/WhiteboxParametricRuleTests.swift index a2106691..829e98c6 100644 --- a/Tests/LindenmayerTests/WhiteboxParametricRuleTests.swift +++ b/Tests/LindenmayerTests/WhiteboxParametricRuleTests.swift @@ -18,8 +18,8 @@ final class WhiteboxParametricRuleTests: XCTestCase { let p = ParameterizedExample() - func testRuleDefaults() throws { - let r = RewriteRuleDirectDefinesRNG(directType: ParameterizedExample.self, parameters: ParametersWrapper(ExampleDefines()), prng: RNGWrapper(Xoshiro(seed: 0)), where: nil) { _, p, _ -> [Module] in + func testRuleDefaults() async throws { + let r = RewriteRuleDirectDefinesRNG(directType: ParameterizedExample.self, parameters: ExampleDefines(), prng: RNGWrapper(Xoshiro(seed: 0)), where: nil) { _, p, _ -> [Module] in [ParameterizedExample(p.value + 1.0)] } @@ -33,7 +33,7 @@ final class WhiteboxParametricRuleTests: XCTestCase { let differentValueModuleSet = ModuleSet(directInstance: ParameterizedExample(21)) XCTAssertEqual(r.evaluate(differentValueModuleSet), true) - let newModules: [Module] = r.produce(moduleSet) + let newModules: [Module] = await r.produce(moduleSet) XCTAssertEqual(newModules.count, 1) let param = newModules[0] as! ParameterizedExample // verify that our rule was processed, returning the same module with @@ -41,9 +41,9 @@ final class WhiteboxParametricRuleTests: XCTestCase { XCTAssertEqual(param.i, 11) } - func testRuleDefaultsWithSystemParameters() throws { + func testRuleDefaultsWithSystemParameters() async throws { let r = RewriteRuleDirectDefinesRNG(directType: ParameterizedExample.self, - parameters: ParametersWrapper(ExampleDefines()), + parameters: ExampleDefines(), prng: RNGWrapper(Xoshiro(seed: 0)), where: nil) { _, p, _ -> [Module] in @@ -61,7 +61,7 @@ final class WhiteboxParametricRuleTests: XCTestCase { XCTAssertEqual(r.evaluate(differentValueModuleSet), true) let set = ModuleSet(directInstance: ParameterizedExample(10)) - let newModules: [Module] = r.produce(set) + let newModules: [Module] = await r.produce(set) XCTAssertEqual(newModules.count, 1) let param = newModules[0] as! ParameterizedExample // verify that our rule was processed, returning the same module with diff --git a/Tests/LindenmayerTests/WhiteboxRuleTests.swift b/Tests/LindenmayerTests/WhiteboxRuleTests.swift index 3c947017..d362d4cc 100644 --- a/Tests/LindenmayerTests/WhiteboxRuleTests.swift +++ b/Tests/LindenmayerTests/WhiteboxRuleTests.swift @@ -15,7 +15,7 @@ final class WhiteboxRuleTests: XCTestCase { XCTAssertEqual(String(describing: type(of: r.matchingType)), "Internode.Type") } - func testRuleProduction() throws { + func testRuleProduction() async throws { let r = RewriteRuleDirectRNG(directType: Examples2D.Internode.self, prng: RNGWrapper(Xoshiro(seed: 0)), where: nil) { _, _ in [Examples2D.Internode()] } @@ -23,7 +23,7 @@ final class WhiteboxRuleTests: XCTestCase { let set = ModuleSet(directInstance: Examples2D.Internode()) // Verify produce returns an Internode - let newModule = r.produce(set) + let newModule = await r.produce(set) XCTAssertEqual(newModule.count, 1) XCTAssertEqual(newModule[0].description, "I") }