From c7660bcd24e31ef2fc3457f56a2bf4a58c3ad6ee Mon Sep 17 00:00:00 2001 From: stackotter Date: Thu, 27 Jan 2022 19:00:26 +1000 Subject: [PATCH 1/3] Increase family limit from 8 components to 16 components --- .../Generated/Family.generated.swift | 1339 ++++++++++++++++- Sources/FirebladeECS/Stencils/Family.stencil | 2 +- 2 files changed, 1314 insertions(+), 27 deletions(-) diff --git a/Sources/FirebladeECS/Generated/Family.generated.swift b/Sources/FirebladeECS/Generated/Family.generated.swift index caa2ff2e..5e9147d3 100644 --- a/Sources/FirebladeECS/Generated/Family.generated.swift +++ b/Sources/FirebladeECS/Generated/Family.generated.swift @@ -1,6 +1,5 @@ -// Generated using Sourcery 1.0.0 — https://github.com/krzysztofzablocki/Sourcery +// Generated using Sourcery 1.6.1 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT - // swiftlint:disable file_length // swiftlint:disable function_parameter_count // swiftlint:disable large_tuple @@ -28,7 +27,7 @@ public struct Requires1: FamilyRequirementsManaging where Comp1: Componen } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1) { - let entity = Entity(nexus: nexus, id: entityId) + let entity: Entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) return (entity, comp1) } @@ -40,9 +39,9 @@ public struct Requires1: FamilyRequirementsManaging where Comp1: Componen extension Requires1: RequiringComponents1 { } -extension FamilyMemberBuilder where R: RequiringComponents1 { +extension FamilyMemberBuilder where R: RequiringComponents1 { public static func buildBlock(_ comp1: R.Comp1) -> (R.Components) { - (comp1) + return (comp1) } } @@ -122,7 +121,7 @@ public struct Requires2: FamilyRequirementsManaging where Comp1: C } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2) { - let entity = Entity(nexus: nexus, id: entityId) + let entity: Entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) return (entity, comp1, comp2) @@ -135,9 +134,9 @@ public struct Requires2: FamilyRequirementsManaging where Comp1: C extension Requires2: RequiringComponents2 { } -extension FamilyMemberBuilder where R: RequiringComponents2 { +extension FamilyMemberBuilder where R: RequiringComponents2 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2) -> (R.Components) { - (comp1, comp2) + return (comp1, comp2) } } @@ -222,7 +221,7 @@ public struct Requires3: FamilyRequirementsManaging where C } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3) { - let entity = Entity(nexus: nexus, id: entityId) + let entity: Entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -236,9 +235,9 @@ public struct Requires3: FamilyRequirementsManaging where C extension Requires3: RequiringComponents3 { } -extension FamilyMemberBuilder where R: RequiringComponents3 { +extension FamilyMemberBuilder where R: RequiringComponents3 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3) -> (R.Components) { - (comp1, comp2, comp3) + return (comp1, comp2, comp3) } } @@ -328,7 +327,7 @@ public struct Requires4: FamilyRequirementsManaging } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4) { - let entity = Entity(nexus: nexus, id: entityId) + let entity: Entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -343,9 +342,9 @@ public struct Requires4: FamilyRequirementsManaging extension Requires4: RequiringComponents4 { } -extension FamilyMemberBuilder where R: RequiringComponents4 { +extension FamilyMemberBuilder where R: RequiringComponents4 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4) -> (R.Components) { - (comp1, comp2, comp3, comp4) + return (comp1, comp2, comp3, comp4) } } @@ -440,7 +439,7 @@ public struct Requires5: FamilyRequirementsMa } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5) { - let entity = Entity(nexus: nexus, id: entityId) + let entity: Entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -456,9 +455,9 @@ public struct Requires5: FamilyRequirementsMa extension Requires5: RequiringComponents5 { } -extension FamilyMemberBuilder where R: RequiringComponents5 { +extension FamilyMemberBuilder where R: RequiringComponents5 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5) -> (R.Components) { - (comp1, comp2, comp3, comp4, comp5) + return (comp1, comp2, comp3, comp4, comp5) } } @@ -558,7 +557,7 @@ public struct Requires6: FamilyRequire } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6) { - let entity = Entity(nexus: nexus, id: entityId) + let entity: Entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -575,9 +574,9 @@ public struct Requires6: FamilyRequire extension Requires6: RequiringComponents6 { } -extension FamilyMemberBuilder where R: RequiringComponents6 { +extension FamilyMemberBuilder where R: RequiringComponents6 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6) -> (R.Components) { - (comp1, comp2, comp3, comp4, comp5, comp6) + return (comp1, comp2, comp3, comp4, comp5, comp6) } } @@ -682,7 +681,7 @@ public struct Requires7: Family } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7) { - let entity = Entity(nexus: nexus, id: entityId) + let entity: Entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -700,9 +699,9 @@ public struct Requires7: Family extension Requires7: RequiringComponents7 { } -extension FamilyMemberBuilder where R: RequiringComponents7 { +extension FamilyMemberBuilder where R: RequiringComponents7 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6, _ comp7: R.Comp7) -> (R.Components) { - (comp1, comp2, comp3, comp4, comp5, comp6, comp7) + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7) } } @@ -812,7 +811,7 @@ public struct Requires8: } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8) { - let entity = Entity(nexus: nexus, id: entityId) + let entity: Entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -831,9 +830,9 @@ public struct Requires8: extension Requires8: RequiringComponents8 { } -extension FamilyMemberBuilder where R: RequiringComponents8 { +extension FamilyMemberBuilder where R: RequiringComponents8 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6, _ comp7: R.Comp7, _ comp8: R.Comp8) -> (R.Components) { - (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8) + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8) } } @@ -910,3 +909,1291 @@ extension Nexus { ) } } + +// MARK: - Family 9 + +public typealias Family9 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component + +public protocol RequiringComponents9: FamilyRequirementsManaging where Components == (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9) { + associatedtype Comp1: Component + associatedtype Comp2: Component + associatedtype Comp3: Component + associatedtype Comp4: Component + associatedtype Comp5: Component + associatedtype Comp6: Component + associatedtype Comp7: Component + associatedtype Comp8: Component + associatedtype Comp9: Component +} + +public struct Requires9: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type, Comp6.Type, Comp7.Type, Comp8.Type, Comp9.Type)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9) { + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9) { + let entity: Entity = Entity(nexus: nexus, id: entityId) + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5, components.6, components.7, components.8) + } +} + +extension Requires9: RequiringComponents9 { } + +extension FamilyMemberBuilder where R: RequiringComponents9 { + public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6, _ comp7: R.Comp7, _ comp8: R.Comp8, _ comp9: R.Comp9) -> (R.Components) { + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9) + } +} + +extension Requires9: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable, Comp7: Encodable, Comp8: Encodable, Comp9: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { + try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self)) + try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self)) + try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self)) + try container.encode(components.3, forKey: strategy.codingKey(for: Comp4.self)) + try container.encode(components.4, forKey: strategy.codingKey(for: Comp5.self)) + try container.encode(components.5, forKey: strategy.codingKey(for: Comp6.self)) + try container.encode(components.6, forKey: strategy.codingKey(for: Comp7.self)) + try container.encode(components.7, forKey: strategy.codingKey(for: Comp8.self)) + try container.encode(components.8, forKey: strategy.codingKey(for: Comp9.self)) + } +} + +extension Requires9: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable, Comp7: Decodable, Comp8: Decodable, Comp9: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9) { + let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self)) + let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self)) + let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self)) + let comp4 = try container.decode(Comp4.self, forKey: strategy.codingKey(for: Comp4.self)) + let comp5 = try container.decode(Comp5.self, forKey: strategy.codingKey(for: Comp5.self)) + let comp6 = try container.decode(Comp6.self, forKey: strategy.codingKey(for: Comp6.self)) + let comp7 = try container.decode(Comp7.self, forKey: strategy.codingKey(for: Comp7.self)) + let comp8 = try container.decode(Comp8.self, forKey: strategy.codingKey(for: Comp8.self)) + let comp9 = try container.decode(Comp9.self, forKey: strategy.codingKey(for: Comp9.self)) + return Components(comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9) + } +} + +extension Nexus { + /// Create a family of entities (aka members) having 9 required components. + /// + /// A family is a collection of entities with uniform component types per entity. + /// Entities that are be part of this family will have at least the 9 required components, + /// but may have more components assigned. + /// + /// A family is just a view on (component) data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families with the same requirements provide a view on the same collection of entities (aka members). + /// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **General usage** + /// ```swift + /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9) in + /// ... + /// } + /// ``` + /// **Caveats** + /// - Component types must be unique per family + /// - Component type order is arbitrary + /// + /// - Parameters: + /// - comp1: Component type 1 required by members of this family. + /// - comp2: Component type 2 required by members of this family. + /// - comp3: Component type 3 required by members of this family. + /// - comp4: Component type 4 required by members of this family. + /// - comp5: Component type 5 required by members of this family. + /// - comp6: Component type 6 required by members of this family. + /// - comp7: Component type 7 required by members of this family. + /// - comp8: Component type 8 required by members of this family. + /// - comp9: Component type 9 required by members of this family. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 9 required components each. + public func family( + requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type, _ comp6: Comp6.Type, _ comp7: Comp7.Type, _ comp8: Comp8.Type, _ comp9: Comp9.Type, + excludesAll excludedComponents: Component.Type... + ) -> Family9 where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component { + Family9( + nexus: self, + requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9), + excludesAll: excludedComponents + ) + } +} + +// MARK: - Family 10 + +public typealias Family10 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component + +public protocol RequiringComponents10: FamilyRequirementsManaging where Components == (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10) { + associatedtype Comp1: Component + associatedtype Comp2: Component + associatedtype Comp3: Component + associatedtype Comp4: Component + associatedtype Comp5: Component + associatedtype Comp6: Component + associatedtype Comp7: Component + associatedtype Comp8: Component + associatedtype Comp9: Component + associatedtype Comp10: Component +} + +public struct Requires10: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type, Comp6.Type, Comp7.Type, Comp8.Type, Comp9.Type, Comp10.Type)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10) { + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10) { + let entity: Entity = Entity(nexus: nexus, id: entityId) + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5, components.6, components.7, components.8, components.9) + } +} + +extension Requires10: RequiringComponents10 { } + +extension FamilyMemberBuilder where R: RequiringComponents10 { + public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6, _ comp7: R.Comp7, _ comp8: R.Comp8, _ comp9: R.Comp9, _ comp10: R.Comp10) -> (R.Components) { + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10) + } +} + +extension Requires10: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable, Comp7: Encodable, Comp8: Encodable, Comp9: Encodable, Comp10: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { + try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self)) + try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self)) + try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self)) + try container.encode(components.3, forKey: strategy.codingKey(for: Comp4.self)) + try container.encode(components.4, forKey: strategy.codingKey(for: Comp5.self)) + try container.encode(components.5, forKey: strategy.codingKey(for: Comp6.self)) + try container.encode(components.6, forKey: strategy.codingKey(for: Comp7.self)) + try container.encode(components.7, forKey: strategy.codingKey(for: Comp8.self)) + try container.encode(components.8, forKey: strategy.codingKey(for: Comp9.self)) + try container.encode(components.9, forKey: strategy.codingKey(for: Comp10.self)) + } +} + +extension Requires10: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable, Comp7: Decodable, Comp8: Decodable, Comp9: Decodable, Comp10: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10) { + let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self)) + let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self)) + let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self)) + let comp4 = try container.decode(Comp4.self, forKey: strategy.codingKey(for: Comp4.self)) + let comp5 = try container.decode(Comp5.self, forKey: strategy.codingKey(for: Comp5.self)) + let comp6 = try container.decode(Comp6.self, forKey: strategy.codingKey(for: Comp6.self)) + let comp7 = try container.decode(Comp7.self, forKey: strategy.codingKey(for: Comp7.self)) + let comp8 = try container.decode(Comp8.self, forKey: strategy.codingKey(for: Comp8.self)) + let comp9 = try container.decode(Comp9.self, forKey: strategy.codingKey(for: Comp9.self)) + let comp10 = try container.decode(Comp10.self, forKey: strategy.codingKey(for: Comp10.self)) + return Components(comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10) + } +} + +extension Nexus { + /// Create a family of entities (aka members) having 10 required components. + /// + /// A family is a collection of entities with uniform component types per entity. + /// Entities that are be part of this family will have at least the 10 required components, + /// but may have more components assigned. + /// + /// A family is just a view on (component) data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families with the same requirements provide a view on the same collection of entities (aka members). + /// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **General usage** + /// ```swift + /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10) in + /// ... + /// } + /// ``` + /// **Caveats** + /// - Component types must be unique per family + /// - Component type order is arbitrary + /// + /// - Parameters: + /// - comp1: Component type 1 required by members of this family. + /// - comp2: Component type 2 required by members of this family. + /// - comp3: Component type 3 required by members of this family. + /// - comp4: Component type 4 required by members of this family. + /// - comp5: Component type 5 required by members of this family. + /// - comp6: Component type 6 required by members of this family. + /// - comp7: Component type 7 required by members of this family. + /// - comp8: Component type 8 required by members of this family. + /// - comp9: Component type 9 required by members of this family. + /// - comp10: Component type 10 required by members of this family. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 10 required components each. + public func family( + requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type, _ comp6: Comp6.Type, _ comp7: Comp7.Type, _ comp8: Comp8.Type, _ comp9: Comp9.Type, _ comp10: Comp10.Type, + excludesAll excludedComponents: Component.Type... + ) -> Family10 where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component { + Family10( + nexus: self, + requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10), + excludesAll: excludedComponents + ) + } +} + +// MARK: - Family 11 + +public typealias Family11 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component + +public protocol RequiringComponents11: FamilyRequirementsManaging where Components == (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11) { + associatedtype Comp1: Component + associatedtype Comp2: Component + associatedtype Comp3: Component + associatedtype Comp4: Component + associatedtype Comp5: Component + associatedtype Comp6: Component + associatedtype Comp7: Component + associatedtype Comp8: Component + associatedtype Comp9: Component + associatedtype Comp10: Component + associatedtype Comp11: Component +} + +public struct Requires11: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type, Comp6.Type, Comp7.Type, Comp8.Type, Comp9.Type, Comp10.Type, Comp11.Type)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self, Comp11.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11) { + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + let comp11: Comp11 = nexus.get(unsafe: entityId) + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11) { + let entity: Entity = Entity(nexus: nexus, id: entityId) + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + let comp11: Comp11 = nexus.get(unsafe: entityId) + return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5, components.6, components.7, components.8, components.9, components.10) + } +} + +extension Requires11: RequiringComponents11 { } + +extension FamilyMemberBuilder where R: RequiringComponents11 { + public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6, _ comp7: R.Comp7, _ comp8: R.Comp8, _ comp9: R.Comp9, _ comp10: R.Comp10, _ comp11: R.Comp11) -> (R.Components) { + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11) + } +} + +extension Requires11: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable, Comp7: Encodable, Comp8: Encodable, Comp9: Encodable, Comp10: Encodable, Comp11: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { + try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self)) + try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self)) + try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self)) + try container.encode(components.3, forKey: strategy.codingKey(for: Comp4.self)) + try container.encode(components.4, forKey: strategy.codingKey(for: Comp5.self)) + try container.encode(components.5, forKey: strategy.codingKey(for: Comp6.self)) + try container.encode(components.6, forKey: strategy.codingKey(for: Comp7.self)) + try container.encode(components.7, forKey: strategy.codingKey(for: Comp8.self)) + try container.encode(components.8, forKey: strategy.codingKey(for: Comp9.self)) + try container.encode(components.9, forKey: strategy.codingKey(for: Comp10.self)) + try container.encode(components.10, forKey: strategy.codingKey(for: Comp11.self)) + } +} + +extension Requires11: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable, Comp7: Decodable, Comp8: Decodable, Comp9: Decodable, Comp10: Decodable, Comp11: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11) { + let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self)) + let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self)) + let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self)) + let comp4 = try container.decode(Comp4.self, forKey: strategy.codingKey(for: Comp4.self)) + let comp5 = try container.decode(Comp5.self, forKey: strategy.codingKey(for: Comp5.self)) + let comp6 = try container.decode(Comp6.self, forKey: strategy.codingKey(for: Comp6.self)) + let comp7 = try container.decode(Comp7.self, forKey: strategy.codingKey(for: Comp7.self)) + let comp8 = try container.decode(Comp8.self, forKey: strategy.codingKey(for: Comp8.self)) + let comp9 = try container.decode(Comp9.self, forKey: strategy.codingKey(for: Comp9.self)) + let comp10 = try container.decode(Comp10.self, forKey: strategy.codingKey(for: Comp10.self)) + let comp11 = try container.decode(Comp11.self, forKey: strategy.codingKey(for: Comp11.self)) + return Components(comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11) + } +} + +extension Nexus { + /// Create a family of entities (aka members) having 11 required components. + /// + /// A family is a collection of entities with uniform component types per entity. + /// Entities that are be part of this family will have at least the 11 required components, + /// but may have more components assigned. + /// + /// A family is just a view on (component) data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families with the same requirements provide a view on the same collection of entities (aka members). + /// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **General usage** + /// ```swift + /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self, Comp11.self) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11) in + /// ... + /// } + /// ``` + /// **Caveats** + /// - Component types must be unique per family + /// - Component type order is arbitrary + /// + /// - Parameters: + /// - comp1: Component type 1 required by members of this family. + /// - comp2: Component type 2 required by members of this family. + /// - comp3: Component type 3 required by members of this family. + /// - comp4: Component type 4 required by members of this family. + /// - comp5: Component type 5 required by members of this family. + /// - comp6: Component type 6 required by members of this family. + /// - comp7: Component type 7 required by members of this family. + /// - comp8: Component type 8 required by members of this family. + /// - comp9: Component type 9 required by members of this family. + /// - comp10: Component type 10 required by members of this family. + /// - comp11: Component type 11 required by members of this family. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 11 required components each. + public func family( + requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type, _ comp6: Comp6.Type, _ comp7: Comp7.Type, _ comp8: Comp8.Type, _ comp9: Comp9.Type, _ comp10: Comp10.Type, _ comp11: Comp11.Type, + excludesAll excludedComponents: Component.Type... + ) -> Family11 where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component { + Family11( + nexus: self, + requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11), + excludesAll: excludedComponents + ) + } +} + +// MARK: - Family 12 + +public typealias Family12 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component + +public protocol RequiringComponents12: FamilyRequirementsManaging where Components == (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12) { + associatedtype Comp1: Component + associatedtype Comp2: Component + associatedtype Comp3: Component + associatedtype Comp4: Component + associatedtype Comp5: Component + associatedtype Comp6: Component + associatedtype Comp7: Component + associatedtype Comp8: Component + associatedtype Comp9: Component + associatedtype Comp10: Component + associatedtype Comp11: Component + associatedtype Comp12: Component +} + +public struct Requires12: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type, Comp6.Type, Comp7.Type, Comp8.Type, Comp9.Type, Comp10.Type, Comp11.Type, Comp12.Type)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self, Comp11.self, Comp12.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12) { + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + let comp11: Comp11 = nexus.get(unsafe: entityId) + let comp12: Comp12 = nexus.get(unsafe: entityId) + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12) { + let entity: Entity = Entity(nexus: nexus, id: entityId) + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + let comp11: Comp11 = nexus.get(unsafe: entityId) + let comp12: Comp12 = nexus.get(unsafe: entityId) + return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5, components.6, components.7, components.8, components.9, components.10, components.11) + } +} + +extension Requires12: RequiringComponents12 { } + +extension FamilyMemberBuilder where R: RequiringComponents12 { + public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6, _ comp7: R.Comp7, _ comp8: R.Comp8, _ comp9: R.Comp9, _ comp10: R.Comp10, _ comp11: R.Comp11, _ comp12: R.Comp12) -> (R.Components) { + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12) + } +} + +extension Requires12: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable, Comp7: Encodable, Comp8: Encodable, Comp9: Encodable, Comp10: Encodable, Comp11: Encodable, Comp12: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { + try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self)) + try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self)) + try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self)) + try container.encode(components.3, forKey: strategy.codingKey(for: Comp4.self)) + try container.encode(components.4, forKey: strategy.codingKey(for: Comp5.self)) + try container.encode(components.5, forKey: strategy.codingKey(for: Comp6.self)) + try container.encode(components.6, forKey: strategy.codingKey(for: Comp7.self)) + try container.encode(components.7, forKey: strategy.codingKey(for: Comp8.self)) + try container.encode(components.8, forKey: strategy.codingKey(for: Comp9.self)) + try container.encode(components.9, forKey: strategy.codingKey(for: Comp10.self)) + try container.encode(components.10, forKey: strategy.codingKey(for: Comp11.self)) + try container.encode(components.11, forKey: strategy.codingKey(for: Comp12.self)) + } +} + +extension Requires12: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable, Comp7: Decodable, Comp8: Decodable, Comp9: Decodable, Comp10: Decodable, Comp11: Decodable, Comp12: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12) { + let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self)) + let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self)) + let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self)) + let comp4 = try container.decode(Comp4.self, forKey: strategy.codingKey(for: Comp4.self)) + let comp5 = try container.decode(Comp5.self, forKey: strategy.codingKey(for: Comp5.self)) + let comp6 = try container.decode(Comp6.self, forKey: strategy.codingKey(for: Comp6.self)) + let comp7 = try container.decode(Comp7.self, forKey: strategy.codingKey(for: Comp7.self)) + let comp8 = try container.decode(Comp8.self, forKey: strategy.codingKey(for: Comp8.self)) + let comp9 = try container.decode(Comp9.self, forKey: strategy.codingKey(for: Comp9.self)) + let comp10 = try container.decode(Comp10.self, forKey: strategy.codingKey(for: Comp10.self)) + let comp11 = try container.decode(Comp11.self, forKey: strategy.codingKey(for: Comp11.self)) + let comp12 = try container.decode(Comp12.self, forKey: strategy.codingKey(for: Comp12.self)) + return Components(comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12) + } +} + +extension Nexus { + /// Create a family of entities (aka members) having 12 required components. + /// + /// A family is a collection of entities with uniform component types per entity. + /// Entities that are be part of this family will have at least the 12 required components, + /// but may have more components assigned. + /// + /// A family is just a view on (component) data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families with the same requirements provide a view on the same collection of entities (aka members). + /// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **General usage** + /// ```swift + /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self, Comp11.self, Comp12.self) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12) in + /// ... + /// } + /// ``` + /// **Caveats** + /// - Component types must be unique per family + /// - Component type order is arbitrary + /// + /// - Parameters: + /// - comp1: Component type 1 required by members of this family. + /// - comp2: Component type 2 required by members of this family. + /// - comp3: Component type 3 required by members of this family. + /// - comp4: Component type 4 required by members of this family. + /// - comp5: Component type 5 required by members of this family. + /// - comp6: Component type 6 required by members of this family. + /// - comp7: Component type 7 required by members of this family. + /// - comp8: Component type 8 required by members of this family. + /// - comp9: Component type 9 required by members of this family. + /// - comp10: Component type 10 required by members of this family. + /// - comp11: Component type 11 required by members of this family. + /// - comp12: Component type 12 required by members of this family. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 12 required components each. + public func family( + requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type, _ comp6: Comp6.Type, _ comp7: Comp7.Type, _ comp8: Comp8.Type, _ comp9: Comp9.Type, _ comp10: Comp10.Type, _ comp11: Comp11.Type, _ comp12: Comp12.Type, + excludesAll excludedComponents: Component.Type... + ) -> Family12 where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component { + Family12( + nexus: self, + requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12), + excludesAll: excludedComponents + ) + } +} + +// MARK: - Family 13 + +public typealias Family13 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component, Comp13: Component + +public protocol RequiringComponents13: FamilyRequirementsManaging where Components == (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13) { + associatedtype Comp1: Component + associatedtype Comp2: Component + associatedtype Comp3: Component + associatedtype Comp4: Component + associatedtype Comp5: Component + associatedtype Comp6: Component + associatedtype Comp7: Component + associatedtype Comp8: Component + associatedtype Comp9: Component + associatedtype Comp10: Component + associatedtype Comp11: Component + associatedtype Comp12: Component + associatedtype Comp13: Component +} + +public struct Requires13: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component, Comp13: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type, Comp6.Type, Comp7.Type, Comp8.Type, Comp9.Type, Comp10.Type, Comp11.Type, Comp12.Type, Comp13.Type)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self, Comp11.self, Comp12.self, Comp13.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13) { + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + let comp11: Comp11 = nexus.get(unsafe: entityId) + let comp12: Comp12 = nexus.get(unsafe: entityId) + let comp13: Comp13 = nexus.get(unsafe: entityId) + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13) { + let entity: Entity = Entity(nexus: nexus, id: entityId) + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + let comp11: Comp11 = nexus.get(unsafe: entityId) + let comp12: Comp12 = nexus.get(unsafe: entityId) + let comp13: Comp13 = nexus.get(unsafe: entityId) + return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5, components.6, components.7, components.8, components.9, components.10, components.11, components.12) + } +} + +extension Requires13: RequiringComponents13 { } + +extension FamilyMemberBuilder where R: RequiringComponents13 { + public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6, _ comp7: R.Comp7, _ comp8: R.Comp8, _ comp9: R.Comp9, _ comp10: R.Comp10, _ comp11: R.Comp11, _ comp12: R.Comp12, _ comp13: R.Comp13) -> (R.Components) { + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13) + } +} + +extension Requires13: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable, Comp7: Encodable, Comp8: Encodable, Comp9: Encodable, Comp10: Encodable, Comp11: Encodable, Comp12: Encodable, Comp13: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { + try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self)) + try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self)) + try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self)) + try container.encode(components.3, forKey: strategy.codingKey(for: Comp4.self)) + try container.encode(components.4, forKey: strategy.codingKey(for: Comp5.self)) + try container.encode(components.5, forKey: strategy.codingKey(for: Comp6.self)) + try container.encode(components.6, forKey: strategy.codingKey(for: Comp7.self)) + try container.encode(components.7, forKey: strategy.codingKey(for: Comp8.self)) + try container.encode(components.8, forKey: strategy.codingKey(for: Comp9.self)) + try container.encode(components.9, forKey: strategy.codingKey(for: Comp10.self)) + try container.encode(components.10, forKey: strategy.codingKey(for: Comp11.self)) + try container.encode(components.11, forKey: strategy.codingKey(for: Comp12.self)) + try container.encode(components.12, forKey: strategy.codingKey(for: Comp13.self)) + } +} + +extension Requires13: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable, Comp7: Decodable, Comp8: Decodable, Comp9: Decodable, Comp10: Decodable, Comp11: Decodable, Comp12: Decodable, Comp13: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13) { + let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self)) + let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self)) + let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self)) + let comp4 = try container.decode(Comp4.self, forKey: strategy.codingKey(for: Comp4.self)) + let comp5 = try container.decode(Comp5.self, forKey: strategy.codingKey(for: Comp5.self)) + let comp6 = try container.decode(Comp6.self, forKey: strategy.codingKey(for: Comp6.self)) + let comp7 = try container.decode(Comp7.self, forKey: strategy.codingKey(for: Comp7.self)) + let comp8 = try container.decode(Comp8.self, forKey: strategy.codingKey(for: Comp8.self)) + let comp9 = try container.decode(Comp9.self, forKey: strategy.codingKey(for: Comp9.self)) + let comp10 = try container.decode(Comp10.self, forKey: strategy.codingKey(for: Comp10.self)) + let comp11 = try container.decode(Comp11.self, forKey: strategy.codingKey(for: Comp11.self)) + let comp12 = try container.decode(Comp12.self, forKey: strategy.codingKey(for: Comp12.self)) + let comp13 = try container.decode(Comp13.self, forKey: strategy.codingKey(for: Comp13.self)) + return Components(comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13) + } +} + +extension Nexus { + /// Create a family of entities (aka members) having 13 required components. + /// + /// A family is a collection of entities with uniform component types per entity. + /// Entities that are be part of this family will have at least the 13 required components, + /// but may have more components assigned. + /// + /// A family is just a view on (component) data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families with the same requirements provide a view on the same collection of entities (aka members). + /// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **General usage** + /// ```swift + /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self, Comp11.self, Comp12.self, Comp13.self) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13) in + /// ... + /// } + /// ``` + /// **Caveats** + /// - Component types must be unique per family + /// - Component type order is arbitrary + /// + /// - Parameters: + /// - comp1: Component type 1 required by members of this family. + /// - comp2: Component type 2 required by members of this family. + /// - comp3: Component type 3 required by members of this family. + /// - comp4: Component type 4 required by members of this family. + /// - comp5: Component type 5 required by members of this family. + /// - comp6: Component type 6 required by members of this family. + /// - comp7: Component type 7 required by members of this family. + /// - comp8: Component type 8 required by members of this family. + /// - comp9: Component type 9 required by members of this family. + /// - comp10: Component type 10 required by members of this family. + /// - comp11: Component type 11 required by members of this family. + /// - comp12: Component type 12 required by members of this family. + /// - comp13: Component type 13 required by members of this family. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 13 required components each. + public func family( + requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type, _ comp6: Comp6.Type, _ comp7: Comp7.Type, _ comp8: Comp8.Type, _ comp9: Comp9.Type, _ comp10: Comp10.Type, _ comp11: Comp11.Type, _ comp12: Comp12.Type, _ comp13: Comp13.Type, + excludesAll excludedComponents: Component.Type... + ) -> Family13 where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component, Comp13: Component { + Family13( + nexus: self, + requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13), + excludesAll: excludedComponents + ) + } +} + +// MARK: - Family 14 + +public typealias Family14 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component, Comp13: Component, Comp14: Component + +public protocol RequiringComponents14: FamilyRequirementsManaging where Components == (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14) { + associatedtype Comp1: Component + associatedtype Comp2: Component + associatedtype Comp3: Component + associatedtype Comp4: Component + associatedtype Comp5: Component + associatedtype Comp6: Component + associatedtype Comp7: Component + associatedtype Comp8: Component + associatedtype Comp9: Component + associatedtype Comp10: Component + associatedtype Comp11: Component + associatedtype Comp12: Component + associatedtype Comp13: Component + associatedtype Comp14: Component +} + +public struct Requires14: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component, Comp13: Component, Comp14: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type, Comp6.Type, Comp7.Type, Comp8.Type, Comp9.Type, Comp10.Type, Comp11.Type, Comp12.Type, Comp13.Type, Comp14.Type)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self, Comp11.self, Comp12.self, Comp13.self, Comp14.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14) { + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + let comp11: Comp11 = nexus.get(unsafe: entityId) + let comp12: Comp12 = nexus.get(unsafe: entityId) + let comp13: Comp13 = nexus.get(unsafe: entityId) + let comp14: Comp14 = nexus.get(unsafe: entityId) + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14) { + let entity: Entity = Entity(nexus: nexus, id: entityId) + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + let comp11: Comp11 = nexus.get(unsafe: entityId) + let comp12: Comp12 = nexus.get(unsafe: entityId) + let comp13: Comp13 = nexus.get(unsafe: entityId) + let comp14: Comp14 = nexus.get(unsafe: entityId) + return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5, components.6, components.7, components.8, components.9, components.10, components.11, components.12, components.13) + } +} + +extension Requires14: RequiringComponents14 { } + +extension FamilyMemberBuilder where R: RequiringComponents14 { + public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6, _ comp7: R.Comp7, _ comp8: R.Comp8, _ comp9: R.Comp9, _ comp10: R.Comp10, _ comp11: R.Comp11, _ comp12: R.Comp12, _ comp13: R.Comp13, _ comp14: R.Comp14) -> (R.Components) { + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14) + } +} + +extension Requires14: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable, Comp7: Encodable, Comp8: Encodable, Comp9: Encodable, Comp10: Encodable, Comp11: Encodable, Comp12: Encodable, Comp13: Encodable, Comp14: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { + try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self)) + try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self)) + try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self)) + try container.encode(components.3, forKey: strategy.codingKey(for: Comp4.self)) + try container.encode(components.4, forKey: strategy.codingKey(for: Comp5.self)) + try container.encode(components.5, forKey: strategy.codingKey(for: Comp6.self)) + try container.encode(components.6, forKey: strategy.codingKey(for: Comp7.self)) + try container.encode(components.7, forKey: strategy.codingKey(for: Comp8.self)) + try container.encode(components.8, forKey: strategy.codingKey(for: Comp9.self)) + try container.encode(components.9, forKey: strategy.codingKey(for: Comp10.self)) + try container.encode(components.10, forKey: strategy.codingKey(for: Comp11.self)) + try container.encode(components.11, forKey: strategy.codingKey(for: Comp12.self)) + try container.encode(components.12, forKey: strategy.codingKey(for: Comp13.self)) + try container.encode(components.13, forKey: strategy.codingKey(for: Comp14.self)) + } +} + +extension Requires14: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable, Comp7: Decodable, Comp8: Decodable, Comp9: Decodable, Comp10: Decodable, Comp11: Decodable, Comp12: Decodable, Comp13: Decodable, Comp14: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14) { + let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self)) + let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self)) + let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self)) + let comp4 = try container.decode(Comp4.self, forKey: strategy.codingKey(for: Comp4.self)) + let comp5 = try container.decode(Comp5.self, forKey: strategy.codingKey(for: Comp5.self)) + let comp6 = try container.decode(Comp6.self, forKey: strategy.codingKey(for: Comp6.self)) + let comp7 = try container.decode(Comp7.self, forKey: strategy.codingKey(for: Comp7.self)) + let comp8 = try container.decode(Comp8.self, forKey: strategy.codingKey(for: Comp8.self)) + let comp9 = try container.decode(Comp9.self, forKey: strategy.codingKey(for: Comp9.self)) + let comp10 = try container.decode(Comp10.self, forKey: strategy.codingKey(for: Comp10.self)) + let comp11 = try container.decode(Comp11.self, forKey: strategy.codingKey(for: Comp11.self)) + let comp12 = try container.decode(Comp12.self, forKey: strategy.codingKey(for: Comp12.self)) + let comp13 = try container.decode(Comp13.self, forKey: strategy.codingKey(for: Comp13.self)) + let comp14 = try container.decode(Comp14.self, forKey: strategy.codingKey(for: Comp14.self)) + return Components(comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14) + } +} + +extension Nexus { + /// Create a family of entities (aka members) having 14 required components. + /// + /// A family is a collection of entities with uniform component types per entity. + /// Entities that are be part of this family will have at least the 14 required components, + /// but may have more components assigned. + /// + /// A family is just a view on (component) data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families with the same requirements provide a view on the same collection of entities (aka members). + /// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **General usage** + /// ```swift + /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self, Comp11.self, Comp12.self, Comp13.self, Comp14.self) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14) in + /// ... + /// } + /// ``` + /// **Caveats** + /// - Component types must be unique per family + /// - Component type order is arbitrary + /// + /// - Parameters: + /// - comp1: Component type 1 required by members of this family. + /// - comp2: Component type 2 required by members of this family. + /// - comp3: Component type 3 required by members of this family. + /// - comp4: Component type 4 required by members of this family. + /// - comp5: Component type 5 required by members of this family. + /// - comp6: Component type 6 required by members of this family. + /// - comp7: Component type 7 required by members of this family. + /// - comp8: Component type 8 required by members of this family. + /// - comp9: Component type 9 required by members of this family. + /// - comp10: Component type 10 required by members of this family. + /// - comp11: Component type 11 required by members of this family. + /// - comp12: Component type 12 required by members of this family. + /// - comp13: Component type 13 required by members of this family. + /// - comp14: Component type 14 required by members of this family. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 14 required components each. + public func family( + requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type, _ comp6: Comp6.Type, _ comp7: Comp7.Type, _ comp8: Comp8.Type, _ comp9: Comp9.Type, _ comp10: Comp10.Type, _ comp11: Comp11.Type, _ comp12: Comp12.Type, _ comp13: Comp13.Type, _ comp14: Comp14.Type, + excludesAll excludedComponents: Component.Type... + ) -> Family14 where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component, Comp13: Component, Comp14: Component { + Family14( + nexus: self, + requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14), + excludesAll: excludedComponents + ) + } +} + +// MARK: - Family 15 + +public typealias Family15 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component, Comp13: Component, Comp14: Component, Comp15: Component + +public protocol RequiringComponents15: FamilyRequirementsManaging where Components == (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15) { + associatedtype Comp1: Component + associatedtype Comp2: Component + associatedtype Comp3: Component + associatedtype Comp4: Component + associatedtype Comp5: Component + associatedtype Comp6: Component + associatedtype Comp7: Component + associatedtype Comp8: Component + associatedtype Comp9: Component + associatedtype Comp10: Component + associatedtype Comp11: Component + associatedtype Comp12: Component + associatedtype Comp13: Component + associatedtype Comp14: Component + associatedtype Comp15: Component +} + +public struct Requires15: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component, Comp13: Component, Comp14: Component, Comp15: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type, Comp6.Type, Comp7.Type, Comp8.Type, Comp9.Type, Comp10.Type, Comp11.Type, Comp12.Type, Comp13.Type, Comp14.Type, Comp15.Type)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self, Comp11.self, Comp12.self, Comp13.self, Comp14.self, Comp15.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15) { + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + let comp11: Comp11 = nexus.get(unsafe: entityId) + let comp12: Comp12 = nexus.get(unsafe: entityId) + let comp13: Comp13 = nexus.get(unsafe: entityId) + let comp14: Comp14 = nexus.get(unsafe: entityId) + let comp15: Comp15 = nexus.get(unsafe: entityId) + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15) { + let entity: Entity = Entity(nexus: nexus, id: entityId) + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + let comp11: Comp11 = nexus.get(unsafe: entityId) + let comp12: Comp12 = nexus.get(unsafe: entityId) + let comp13: Comp13 = nexus.get(unsafe: entityId) + let comp14: Comp14 = nexus.get(unsafe: entityId) + let comp15: Comp15 = nexus.get(unsafe: entityId) + return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5, components.6, components.7, components.8, components.9, components.10, components.11, components.12, components.13, components.14) + } +} + +extension Requires15: RequiringComponents15 { } + +extension FamilyMemberBuilder where R: RequiringComponents15 { + public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6, _ comp7: R.Comp7, _ comp8: R.Comp8, _ comp9: R.Comp9, _ comp10: R.Comp10, _ comp11: R.Comp11, _ comp12: R.Comp12, _ comp13: R.Comp13, _ comp14: R.Comp14, _ comp15: R.Comp15) -> (R.Components) { + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15) + } +} + +extension Requires15: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable, Comp7: Encodable, Comp8: Encodable, Comp9: Encodable, Comp10: Encodable, Comp11: Encodable, Comp12: Encodable, Comp13: Encodable, Comp14: Encodable, Comp15: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { + try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self)) + try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self)) + try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self)) + try container.encode(components.3, forKey: strategy.codingKey(for: Comp4.self)) + try container.encode(components.4, forKey: strategy.codingKey(for: Comp5.self)) + try container.encode(components.5, forKey: strategy.codingKey(for: Comp6.self)) + try container.encode(components.6, forKey: strategy.codingKey(for: Comp7.self)) + try container.encode(components.7, forKey: strategy.codingKey(for: Comp8.self)) + try container.encode(components.8, forKey: strategy.codingKey(for: Comp9.self)) + try container.encode(components.9, forKey: strategy.codingKey(for: Comp10.self)) + try container.encode(components.10, forKey: strategy.codingKey(for: Comp11.self)) + try container.encode(components.11, forKey: strategy.codingKey(for: Comp12.self)) + try container.encode(components.12, forKey: strategy.codingKey(for: Comp13.self)) + try container.encode(components.13, forKey: strategy.codingKey(for: Comp14.self)) + try container.encode(components.14, forKey: strategy.codingKey(for: Comp15.self)) + } +} + +extension Requires15: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable, Comp7: Decodable, Comp8: Decodable, Comp9: Decodable, Comp10: Decodable, Comp11: Decodable, Comp12: Decodable, Comp13: Decodable, Comp14: Decodable, Comp15: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15) { + let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self)) + let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self)) + let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self)) + let comp4 = try container.decode(Comp4.self, forKey: strategy.codingKey(for: Comp4.self)) + let comp5 = try container.decode(Comp5.self, forKey: strategy.codingKey(for: Comp5.self)) + let comp6 = try container.decode(Comp6.self, forKey: strategy.codingKey(for: Comp6.self)) + let comp7 = try container.decode(Comp7.self, forKey: strategy.codingKey(for: Comp7.self)) + let comp8 = try container.decode(Comp8.self, forKey: strategy.codingKey(for: Comp8.self)) + let comp9 = try container.decode(Comp9.self, forKey: strategy.codingKey(for: Comp9.self)) + let comp10 = try container.decode(Comp10.self, forKey: strategy.codingKey(for: Comp10.self)) + let comp11 = try container.decode(Comp11.self, forKey: strategy.codingKey(for: Comp11.self)) + let comp12 = try container.decode(Comp12.self, forKey: strategy.codingKey(for: Comp12.self)) + let comp13 = try container.decode(Comp13.self, forKey: strategy.codingKey(for: Comp13.self)) + let comp14 = try container.decode(Comp14.self, forKey: strategy.codingKey(for: Comp14.self)) + let comp15 = try container.decode(Comp15.self, forKey: strategy.codingKey(for: Comp15.self)) + return Components(comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15) + } +} + +extension Nexus { + /// Create a family of entities (aka members) having 15 required components. + /// + /// A family is a collection of entities with uniform component types per entity. + /// Entities that are be part of this family will have at least the 15 required components, + /// but may have more components assigned. + /// + /// A family is just a view on (component) data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families with the same requirements provide a view on the same collection of entities (aka members). + /// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **General usage** + /// ```swift + /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self, Comp11.self, Comp12.self, Comp13.self, Comp14.self, Comp15.self) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15) in + /// ... + /// } + /// ``` + /// **Caveats** + /// - Component types must be unique per family + /// - Component type order is arbitrary + /// + /// - Parameters: + /// - comp1: Component type 1 required by members of this family. + /// - comp2: Component type 2 required by members of this family. + /// - comp3: Component type 3 required by members of this family. + /// - comp4: Component type 4 required by members of this family. + /// - comp5: Component type 5 required by members of this family. + /// - comp6: Component type 6 required by members of this family. + /// - comp7: Component type 7 required by members of this family. + /// - comp8: Component type 8 required by members of this family. + /// - comp9: Component type 9 required by members of this family. + /// - comp10: Component type 10 required by members of this family. + /// - comp11: Component type 11 required by members of this family. + /// - comp12: Component type 12 required by members of this family. + /// - comp13: Component type 13 required by members of this family. + /// - comp14: Component type 14 required by members of this family. + /// - comp15: Component type 15 required by members of this family. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 15 required components each. + public func family( + requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type, _ comp6: Comp6.Type, _ comp7: Comp7.Type, _ comp8: Comp8.Type, _ comp9: Comp9.Type, _ comp10: Comp10.Type, _ comp11: Comp11.Type, _ comp12: Comp12.Type, _ comp13: Comp13.Type, _ comp14: Comp14.Type, _ comp15: Comp15.Type, + excludesAll excludedComponents: Component.Type... + ) -> Family15 where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component, Comp13: Component, Comp14: Component, Comp15: Component { + Family15( + nexus: self, + requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15), + excludesAll: excludedComponents + ) + } +} + +// MARK: - Family 16 + +public typealias Family16 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component, Comp13: Component, Comp14: Component, Comp15: Component, Comp16: Component + +public protocol RequiringComponents16: FamilyRequirementsManaging where Components == (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15, Comp16) { + associatedtype Comp1: Component + associatedtype Comp2: Component + associatedtype Comp3: Component + associatedtype Comp4: Component + associatedtype Comp5: Component + associatedtype Comp6: Component + associatedtype Comp7: Component + associatedtype Comp8: Component + associatedtype Comp9: Component + associatedtype Comp10: Component + associatedtype Comp11: Component + associatedtype Comp12: Component + associatedtype Comp13: Component + associatedtype Comp14: Component + associatedtype Comp15: Component + associatedtype Comp16: Component +} + +public struct Requires16: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component, Comp13: Component, Comp14: Component, Comp15: Component, Comp16: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type, Comp6.Type, Comp7.Type, Comp8.Type, Comp9.Type, Comp10.Type, Comp11.Type, Comp12.Type, Comp13.Type, Comp14.Type, Comp15.Type, Comp16.Type)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self, Comp11.self, Comp12.self, Comp13.self, Comp14.self, Comp15.self, Comp16.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15, Comp16) { + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + let comp11: Comp11 = nexus.get(unsafe: entityId) + let comp12: Comp12 = nexus.get(unsafe: entityId) + let comp13: Comp13 = nexus.get(unsafe: entityId) + let comp14: Comp14 = nexus.get(unsafe: entityId) + let comp15: Comp15 = nexus.get(unsafe: entityId) + let comp16: Comp16 = nexus.get(unsafe: entityId) + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15, comp16) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15, Comp16) { + let entity: Entity = Entity(nexus: nexus, id: entityId) + let comp1: Comp1 = nexus.get(unsafe: entityId) + let comp2: Comp2 = nexus.get(unsafe: entityId) + let comp3: Comp3 = nexus.get(unsafe: entityId) + let comp4: Comp4 = nexus.get(unsafe: entityId) + let comp5: Comp5 = nexus.get(unsafe: entityId) + let comp6: Comp6 = nexus.get(unsafe: entityId) + let comp7: Comp7 = nexus.get(unsafe: entityId) + let comp8: Comp8 = nexus.get(unsafe: entityId) + let comp9: Comp9 = nexus.get(unsafe: entityId) + let comp10: Comp10 = nexus.get(unsafe: entityId) + let comp11: Comp11 = nexus.get(unsafe: entityId) + let comp12: Comp12 = nexus.get(unsafe: entityId) + let comp13: Comp13 = nexus.get(unsafe: entityId) + let comp14: Comp14 = nexus.get(unsafe: entityId) + let comp15: Comp15 = nexus.get(unsafe: entityId) + let comp16: Comp16 = nexus.get(unsafe: entityId) + return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15, comp16) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15, Comp16)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5, components.6, components.7, components.8, components.9, components.10, components.11, components.12, components.13, components.14, components.15) + } +} + +extension Requires16: RequiringComponents16 { } + +extension FamilyMemberBuilder where R: RequiringComponents16 { + public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6, _ comp7: R.Comp7, _ comp8: R.Comp8, _ comp9: R.Comp9, _ comp10: R.Comp10, _ comp11: R.Comp11, _ comp12: R.Comp12, _ comp13: R.Comp13, _ comp14: R.Comp14, _ comp15: R.Comp15, _ comp16: R.Comp16) -> (R.Components) { + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15, comp16) + } +} + +extension Requires16: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable, Comp7: Encodable, Comp8: Encodable, Comp9: Encodable, Comp10: Encodable, Comp11: Encodable, Comp12: Encodable, Comp13: Encodable, Comp14: Encodable, Comp15: Encodable, Comp16: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15, Comp16), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { + try container.encode(components.0, forKey: strategy.codingKey(for: Comp1.self)) + try container.encode(components.1, forKey: strategy.codingKey(for: Comp2.self)) + try container.encode(components.2, forKey: strategy.codingKey(for: Comp3.self)) + try container.encode(components.3, forKey: strategy.codingKey(for: Comp4.self)) + try container.encode(components.4, forKey: strategy.codingKey(for: Comp5.self)) + try container.encode(components.5, forKey: strategy.codingKey(for: Comp6.self)) + try container.encode(components.6, forKey: strategy.codingKey(for: Comp7.self)) + try container.encode(components.7, forKey: strategy.codingKey(for: Comp8.self)) + try container.encode(components.8, forKey: strategy.codingKey(for: Comp9.self)) + try container.encode(components.9, forKey: strategy.codingKey(for: Comp10.self)) + try container.encode(components.10, forKey: strategy.codingKey(for: Comp11.self)) + try container.encode(components.11, forKey: strategy.codingKey(for: Comp12.self)) + try container.encode(components.12, forKey: strategy.codingKey(for: Comp13.self)) + try container.encode(components.13, forKey: strategy.codingKey(for: Comp14.self)) + try container.encode(components.14, forKey: strategy.codingKey(for: Comp15.self)) + try container.encode(components.15, forKey: strategy.codingKey(for: Comp16.self)) + } +} + +extension Requires16: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable, Comp7: Decodable, Comp8: Decodable, Comp9: Decodable, Comp10: Decodable, Comp11: Decodable, Comp12: Decodable, Comp13: Decodable, Comp14: Decodable, Comp15: Decodable, Comp16: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15, Comp16) { + let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self)) + let comp2 = try container.decode(Comp2.self, forKey: strategy.codingKey(for: Comp2.self)) + let comp3 = try container.decode(Comp3.self, forKey: strategy.codingKey(for: Comp3.self)) + let comp4 = try container.decode(Comp4.self, forKey: strategy.codingKey(for: Comp4.self)) + let comp5 = try container.decode(Comp5.self, forKey: strategy.codingKey(for: Comp5.self)) + let comp6 = try container.decode(Comp6.self, forKey: strategy.codingKey(for: Comp6.self)) + let comp7 = try container.decode(Comp7.self, forKey: strategy.codingKey(for: Comp7.self)) + let comp8 = try container.decode(Comp8.self, forKey: strategy.codingKey(for: Comp8.self)) + let comp9 = try container.decode(Comp9.self, forKey: strategy.codingKey(for: Comp9.self)) + let comp10 = try container.decode(Comp10.self, forKey: strategy.codingKey(for: Comp10.self)) + let comp11 = try container.decode(Comp11.self, forKey: strategy.codingKey(for: Comp11.self)) + let comp12 = try container.decode(Comp12.self, forKey: strategy.codingKey(for: Comp12.self)) + let comp13 = try container.decode(Comp13.self, forKey: strategy.codingKey(for: Comp13.self)) + let comp14 = try container.decode(Comp14.self, forKey: strategy.codingKey(for: Comp14.self)) + let comp15 = try container.decode(Comp15.self, forKey: strategy.codingKey(for: Comp15.self)) + let comp16 = try container.decode(Comp16.self, forKey: strategy.codingKey(for: Comp16.self)) + return Components(comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15, comp16) + } +} + +extension Nexus { + /// Create a family of entities (aka members) having 16 required components. + /// + /// A family is a collection of entities with uniform component types per entity. + /// Entities that are be part of this family will have at least the 16 required components, + /// but may have more components assigned. + /// + /// A family is just a view on (component) data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families with the same requirements provide a view on the same collection of entities (aka members). + /// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **General usage** + /// ```swift + /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self, Comp9.self, Comp10.self, Comp11.self, Comp12.self, Comp13.self, Comp14.self, Comp15.self, Comp16.self) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15, comp16) in + /// ... + /// } + /// ``` + /// **Caveats** + /// - Component types must be unique per family + /// - Component type order is arbitrary + /// + /// - Parameters: + /// - comp1: Component type 1 required by members of this family. + /// - comp2: Component type 2 required by members of this family. + /// - comp3: Component type 3 required by members of this family. + /// - comp4: Component type 4 required by members of this family. + /// - comp5: Component type 5 required by members of this family. + /// - comp6: Component type 6 required by members of this family. + /// - comp7: Component type 7 required by members of this family. + /// - comp8: Component type 8 required by members of this family. + /// - comp9: Component type 9 required by members of this family. + /// - comp10: Component type 10 required by members of this family. + /// - comp11: Component type 11 required by members of this family. + /// - comp12: Component type 12 required by members of this family. + /// - comp13: Component type 13 required by members of this family. + /// - comp14: Component type 14 required by members of this family. + /// - comp15: Component type 15 required by members of this family. + /// - comp16: Component type 16 required by members of this family. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 16 required components each. + public func family( + requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type, _ comp6: Comp6.Type, _ comp7: Comp7.Type, _ comp8: Comp8.Type, _ comp9: Comp9.Type, _ comp10: Comp10.Type, _ comp11: Comp11.Type, _ comp12: Comp12.Type, _ comp13: Comp13.Type, _ comp14: Comp14.Type, _ comp15: Comp15.Type, _ comp16: Comp16.Type, + excludesAll excludedComponents: Component.Type... + ) -> Family16 where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component, Comp9: Component, Comp10: Component, Comp11: Component, Comp12: Component, Comp13: Component, Comp14: Component, Comp15: Component, Comp16: Component { + Family16( + nexus: self, + requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15, comp16), + excludesAll: excludedComponents + ) + } +} diff --git a/Sources/FirebladeECS/Stencils/Family.stencil b/Sources/FirebladeECS/Stencils/Family.stencil index d26dbdff..4739bf1a 100644 --- a/Sources/FirebladeECS/Stencils/Family.stencil +++ b/Sources/FirebladeECS/Stencils/Family.stencil @@ -3,7 +3,7 @@ // swiftlint:disable large_tuple // swiftlint:disable line_length // swiftlint:disable multiline_parameters -{% for idx in 1...8 %} +{% for idx in 1...16 %} {% map 1...idx into components using index %}Comp{{ index }}{% endmap %} {% set CompParams %}{{components|join: ", "}}{% endset %} {% map components into compWhere using comp %}{{ comp }}: Component{% endmap %} From ad7349ad459583dc95374bea279f3c830e78c58d Mon Sep 17 00:00:00 2001 From: stackotter Date: Sat, 26 Mar 2022 12:57:20 +1000 Subject: [PATCH 2/3] Initial changes to convert components to value types --- Sources/FirebladeECS/Component.swift | 2 +- Sources/FirebladeECS/Entity+Component.swift | 2 +- Sources/FirebladeECS/FSM.swift | 832 +++++++------- Sources/FirebladeECS/Nexus+Component.swift | 2 +- Tests/FirebladeECSTests/EntityTests.swift | 32 +- Tests/FirebladeECSTests/FSMTests.swift | 1098 +++++++++---------- 6 files changed, 984 insertions(+), 984 deletions(-) diff --git a/Sources/FirebladeECS/Component.swift b/Sources/FirebladeECS/Component.swift index 23adf943..1e0c52d8 100644 --- a/Sources/FirebladeECS/Component.swift +++ b/Sources/FirebladeECS/Component.swift @@ -8,7 +8,7 @@ /// **Component** /// /// A component represents the raw data for one aspect of an entity. -public protocol Component: AnyObject { +public protocol Component { /// Unique, immutable identifier of this component type. static var identifier: ComponentIdentifier { get } diff --git a/Sources/FirebladeECS/Entity+Component.swift b/Sources/FirebladeECS/Entity+Component.swift index 30100ebb..97380f5f 100644 --- a/Sources/FirebladeECS/Entity+Component.swift +++ b/Sources/FirebladeECS/Entity+Component.swift @@ -48,7 +48,7 @@ extension Entity { self.remove(Comp.self) return } - if self.get(component: componentType) === newComponent { + if self.get(component: componentType) != nil { return } self.assign(newComponent) diff --git a/Sources/FirebladeECS/FSM.swift b/Sources/FirebladeECS/FSM.swift index 9a8de0d9..8d33c248 100644 --- a/Sources/FirebladeECS/FSM.swift +++ b/Sources/FirebladeECS/FSM.swift @@ -11,419 +11,419 @@ public protocol DefaultInitializable { init() } -public typealias ComponentInitializable = Component & DefaultInitializable - -/// This is the Interface for component providers. Component providers are used to supply components -/// for states within an EntityStateMachine. FirebladeECS includes three standard component providers, -/// ComponentTypeProvider, ComponentInstanceProvider and ComponentSingletonProvider. Developers -/// may wish to create more. -public protocol ComponentProvider { - /// Returns an identifier that is used to determine whether two component providers will - /// return the equivalent components. - - /// If an entity is changing state and the state it is leaving and the state is - /// entering have components of the same type, then the identifiers of the component - /// provders are compared. If the two identifiers are the same then the component - /// is not removed. If they are different, the component from the old state is removed - /// and a component for the new state is added. - - /// - Returns: struct/class instance that conforms to Hashable protocol - var identifier: AnyHashable { get } - - /// Used to request a component from the provider. - /// - Returns: A component for use in the state that the entity is entering - func getComponent() -> Component -} - -// MARK: - - -/// This component provider always returns the same instance of the component. The instance -/// is passed to the provider at initialisation. -public final class ComponentInstanceProvider { - private var instance: Component - - /// Initializer - /// - Parameter instance: The instance to return whenever a component is requested. - public init(instance: Component) { - self.instance = instance - } -} - -extension ComponentInstanceProvider: ComponentProvider { - /// Used to compare this provider with others. Any provider that returns the same component - /// instance will be regarded as equivalent. - /// - Returns:ObjectIdentifier of instance - public var identifier: AnyHashable { - ObjectIdentifier(instance) - } - - /// Used to request a component from this provider - /// - Returns: The instance - public func getComponent() -> Component { - instance - } -} - -// MARK: - - -/// This component provider always returns a new instance of a component. An instance -/// is created when requested and is of the type passed in to the initializer. -public final class ComponentTypeProvider { - private var componentType: ComponentInitializable.Type - - /// Used to compare this provider with others. Any ComponentTypeProvider that returns - /// the same type will be regarded as equivalent. - /// - Returns:ObjectIdentifier of the type of the instances created - public let identifier: AnyHashable - - /// Initializer - /// - Parameter type: The type of the instances to be created - public init(type: ComponentInitializable.Type) { - componentType = type - identifier = ObjectIdentifier(componentType.self) - } -} - -extension ComponentTypeProvider: ComponentProvider { - /// Used to request a component from this provider - /// - Returns: A new instance of the type provided in the initializer - public func getComponent() -> Component { - componentType.init() - } -} - -// MARK: - - -/// This component provider always returns the same instance of the component. The instance -/// is created when first required and is of the type passed in to the initializer. -public final class ComponentSingletonProvider { - private lazy var instance: Component = { - componentType.init() - }() - - private var componentType: ComponentInitializable.Type - - /// Initializer - /// - Parameter type: The type of the single instance - public init(type: ComponentInitializable.Type) { - componentType = type - } -} - -extension ComponentSingletonProvider: ComponentProvider { - /// Used to compare this provider with others. Any provider that returns the same single - /// instance will be regarded as equivalent. - /// - Returns: ObjectIdentifier of the single instance - public var identifier: AnyHashable { - ObjectIdentifier(instance) - } - - /// Used to request a component from this provider - /// - Returns: The single instance - public func getComponent() -> Component { - instance - } -} - -// MARK: - - -/// This component provider calls a function to get the component instance. The function must -/// return a single component of the appropriate type. -public final class DynamicComponentProvider { - /// Wrapper for closure to make it hashable via ObjectIdentifier - public final class Closure { - let provideComponent: () -> C - - /// Initializer - /// - Parameter provideComponent: Swift closure returning component of the appropriate type - public init(provideComponent: @escaping () -> C) { - self.provideComponent = provideComponent - } - } - - private let closure: Closure - - /// Initializer - /// - Parameter closure: Instance of Closure class. A wrapper around closure that will - /// return the component instance when called. - public init(closure: Closure) { - self.closure = closure - } -} - -extension DynamicComponentProvider: ComponentProvider { - /// Used to compare this provider with others. Any provider that uses the function or method - /// closure to provide the instance is regarded as equivalent. - /// - Returns: ObjectIdentifier of closure - public var identifier: AnyHashable { - ObjectIdentifier(closure) - } - - /// Used to request a component from this provider - /// - Returns: The instance returned by calling the closure - public func getComponent() -> Component { - closure.provideComponent() - } -} - -// MARK: - - -/// Represents a state for an EntityStateMachine. The state contains any number of ComponentProviders which -/// are used to add components to the entity when this state is entered. -public class EntityState { - internal var providers = [ComponentIdentifier: ComponentProvider]() - - public init() {} - - /// Add a new StateComponentMapping to this state. The mapping is a utility class that is used to - /// map a component type to the provider that provides the component. - /// - Parameter type: The type of component to be mapped - /// - Returns: The component mapping to use when setting the provider for the component - @discardableResult - public func addMapping(for type: ComponentInitializable.Type) -> StateComponentMapping { - StateComponentMapping(creatingState: self, type: type) - } - - /// Get the ComponentProvider for a particular component type. - /// - Parameter type: The type of component to get the provider for - /// - Returns: The ComponentProvider - public func provider(for type: ComponentInitializable.Type) -> ComponentProvider? { - providers[type.identifier] - } - - /// To determine whether this state has a provider for a specific component type. - /// - Parameter type: The type of component to look for a provider for - /// - Returns: true if there is a provider for the given type, false otherwise - public func hasProvider(for type: ComponentInitializable.Type) -> Bool { - providers[type.identifier] != nil - } -} - -/// This extension provides ergonomic way to add component mapping and component -/// provider at once -extension EntityState { - /// Creates a mapping for the component type to a specific component instance. - /// ComponentInstanceProvider is used for the mapping. - /// - Parameter component: The component instance to use for the mapping - /// - Returns: This EntityState, so more modifications can be applied - @discardableResult - @inline(__always) - public func addInstance(_ component: C) -> Self { - addMapping(for: C.self).withInstance(component) - return self - } - - /// Creates a mapping for the component type to new instances of the provided type. - /// A ComponentTypeProvider is used for the mapping. - /// - Parameter type: The type of components to be created by this mapping - /// - Returns: This EntityState, so more modifications can be applied - @inline(__always) - @discardableResult - public func addType(_ type: ComponentInitializable.Type) -> Self { - addMapping(for: type).withType(type) - return self - } - - /// Creates a mapping for the component type to a single instance of the provided type. - /// The instance is not created until it is first requested. - /// A ComponentSingletonProvider is used for the mapping. - /// - Parameter type: The type of the single instance to be created. - /// - Returns: This EntityState, so more modifications can be applied - @inline(__always) - @discardableResult - public func addSingleton(_ type: ComponentInitializable.Type) -> Self { - addMapping(for: type).withSingleton(type) - return self - } - - /// Creates a mapping for the component type to a method call. - /// A DynamicComponentProvider is used for the mapping. - /// - Parameter closure: The Closure instance to return the component instance - /// - Returns: This EntityState, so more modifications can be applied - @inline(__always) - @discardableResult - public func addMethod(closure: DynamicComponentProvider.Closure) -> Self { - addMapping(for: C.self).withMethod(closure) - return self - } - - /// Creates a mapping for the component type to any ComponentProvider. - /// - Parameter type: The type of component to be mapped - /// - Parameter provider: The component provider to use. - /// - Returns: This EntityState, so more modifications can be applied. - @inline(__always) - @discardableResult - public func addProvider(type: C.Type, provider: ComponentProvider) -> Self { - addMapping(for: type).withProvider(provider) - return self - } -} - -// MARK: - - -/// Used by the EntityState class to create the mappings of components to providers via a fluent interface. -public class StateComponentMapping { - private var componentType: ComponentInitializable.Type - private let creatingState: EntityState - private var provider: ComponentProvider - - /// Used internally, the initializer creates a component mapping. The constructor - /// creates a ComponentTypeProvider as the default mapping, which will be replaced - /// by more specific mappings if other methods are called. - /// - Parameter creatingState: The EntityState that the mapping will belong to - /// - Parameter type: The component type for the mapping - internal init(creatingState: EntityState, type: ComponentInitializable.Type) { - self.creatingState = creatingState - componentType = type - provider = ComponentTypeProvider(type: type) - setProvider(provider) - } - - /// Creates a mapping for the component type to a specific component instance. A - /// ComponentInstanceProvider is used for the mapping. - /// - Parameter component: The component instance to use for the mapping - /// - Returns: This ComponentMapping, so more modifications can be applied - @discardableResult - public func withInstance(_ component: Component) -> StateComponentMapping { - setProvider(ComponentInstanceProvider(instance: component)) - return self - } - - /// Creates a mapping for the component type to new instances of the provided type. - /// The type should be the same as or extend the type for this mapping. A ComponentTypeProvider - /// is used for the mapping. - /// - Parameter type: The type of components to be created by this mapping - /// - Returns: This ComponentMapping, so more modifications can be applied - @discardableResult - public func withType(_ type: ComponentInitializable.Type) -> Self { - setProvider(ComponentTypeProvider(type: type)) - return self - } - - /// Creates a mapping for the component type to a single instance of the provided type. - /// The instance is not created until it is first requested. The type should be the same - /// as or extend the type for this mapping. A ComponentSingletonProvider is used for - /// the mapping. - /// - Parameter type: The type of the single instance to be created. If omitted, the type of the - /// mapping is used. - /// - Returns: This ComponentMapping, so more modifications can be applied - @discardableResult - public func withSingleton(_ type: ComponentInitializable.Type?) -> Self { - setProvider(ComponentSingletonProvider(type: type ?? componentType)) - return self - } - - /// Creates a mapping for the component type to a method call. A - /// DynamicComponentProvider is used for the mapping. - /// - Parameter closure: The Closure instance to return the component instance - /// - Returns: This ComponentMapping, so more modifications can be applied - @discardableResult - public func withMethod(_ closure: DynamicComponentProvider.Closure) -> Self { - setProvider(DynamicComponentProvider(closure: closure)) - return self - } - - /// Creates a mapping for the component type to any ComponentProvider. - /// - Parameter provider: The component provider to use. - /// - Returns: This ComponentMapping, so more modifications can be applied. - @discardableResult - public func withProvider(_ provider: ComponentProvider) -> Self { - setProvider(provider) - return self - } - - /// Maps through to the addMapping method of the EntityState that this mapping belongs to - /// so that a fluent interface can be used when configuring entity states. - /// - Parameter type: The type of component to add a mapping to the state for - /// - Returns: The new ComponentMapping for that type - @discardableResult - public func add(_ type: ComponentInitializable.Type) -> StateComponentMapping { - creatingState.addMapping(for: type) - } - - private func setProvider(_ provider: ComponentProvider) { - self.provider = provider - creatingState.providers[componentType.identifier] = provider - } -} - -// MARK: - - -/// This is a state machine for an entity. The state machine manages a set of states, -/// each of which has a set of component providers. When the state machine changes the state, it removes -/// components associated with the previous state and adds components associated with the new state. -/// - Parameter StateIdentifier: Generic hashable state name type -public class EntityStateMachine { - private var states: [StateIdentifier: EntityState] - - /// The current state of the state machine. - private var currentState: EntityState? - - /// The entity whose state machine this is - public var entity: Entity - - /// Initializer. Creates an EntityStateMachine. - public init(entity: Entity) { - self.entity = entity - states = [:] - } - - /// Add a state to this state machine. - /// - Parameter name: The name of this state - used to identify it later in the changeState method call. - /// - Parameter state: The state. - /// - Returns: This state machine, so methods can be chained. - @discardableResult - public func addState(name: StateIdentifier, state: EntityState) -> Self { - states[name] = state - return self - } - - /// Create a new state in this state machine. - /// - Parameter name: The name of the new state - used to identify it later in the changeState method call. - /// - Returns: The new EntityState object that is the state. This will need to be configured with - /// the appropriate component providers. - public func createState(name: StateIdentifier) -> EntityState { - let state = EntityState() - states[name] = state - return state - } - - /// Change to a new state. The components from the old state will be removed and the components - /// for the new state will be added. - /// - Parameter name: The name of the state to change to. - public func changeState(name: StateIdentifier) { - guard let newState = states[name] else { - assertionFailure("Entity state '\(name)' doesn't exist") - return - } - - if newState === currentState { - return - } - - var toAdd: [ComponentIdentifier: ComponentProvider] - - if let currentState = currentState { - toAdd = .init() - for (identifier, provider) in newState.providers { - toAdd[identifier] = provider - } - - for (identifier, _) in currentState.providers { - if let other = toAdd[identifier], let current = currentState.providers[identifier], - current.identifier == other.identifier { - toAdd[identifier] = nil - } else { - entity.remove(identifier) - } - } - } else { - toAdd = newState.providers - } - - for (_, provider) in toAdd { - entity.assign(provider.getComponent()) - } - currentState = newState - } -} +//public typealias ComponentInitializable = Component & DefaultInitializable +// +///// This is the Interface for component providers. Component providers are used to supply components +///// for states within an EntityStateMachine. FirebladeECS includes three standard component providers, +///// ComponentTypeProvider, ComponentInstanceProvider and ComponentSingletonProvider. Developers +///// may wish to create more. +//public protocol ComponentProvider { +// /// Returns an identifier that is used to determine whether two component providers will +// /// return the equivalent components. +// +// /// If an entity is changing state and the state it is leaving and the state is +// /// entering have components of the same type, then the identifiers of the component +// /// provders are compared. If the two identifiers are the same then the component +// /// is not removed. If they are different, the component from the old state is removed +// /// and a component for the new state is added. +// +// /// - Returns: struct/class instance that conforms to Hashable protocol +// var identifier: AnyHashable { get } +// +// /// Used to request a component from the provider. +// /// - Returns: A component for use in the state that the entity is entering +// func getComponent() -> Component +//} +// +//// MARK: - +// +///// This component provider always returns the same instance of the component. The instance +///// is passed to the provider at initialisation. +//public final class ComponentInstanceProvider { +// private var instance: Component +// +// /// Initializer +// /// - Parameter instance: The instance to return whenever a component is requested. +// public init(instance: Component) { +// self.instance = instance +// } +//} +// +//extension ComponentInstanceProvider: ComponentProvider { +// /// Used to compare this provider with others. Any provider that returns the same component +// /// instance will be regarded as equivalent. +// /// - Returns:ObjectIdentifier of instance +// public var identifier: AnyHashable { +// ObjectIdentifier(instance) +// } +// +// /// Used to request a component from this provider +// /// - Returns: The instance +// public func getComponent() -> Component { +// instance +// } +//} +// +//// MARK: - +// +///// This component provider always returns a new instance of a component. An instance +///// is created when requested and is of the type passed in to the initializer. +//public final class ComponentTypeProvider { +// private var componentType: ComponentInitializable.Type +// +// /// Used to compare this provider with others. Any ComponentTypeProvider that returns +// /// the same type will be regarded as equivalent. +// /// - Returns:ObjectIdentifier of the type of the instances created +// public let identifier: AnyHashable +// +// /// Initializer +// /// - Parameter type: The type of the instances to be created +// public init(type: ComponentInitializable.Type) { +// componentType = type +// identifier = ObjectIdentifier(componentType.self) +// } +//} +// +//extension ComponentTypeProvider: ComponentProvider { +// /// Used to request a component from this provider +// /// - Returns: A new instance of the type provided in the initializer +// public func getComponent() -> Component { +// componentType.init() +// } +//} +// +//// MARK: - +// +///// This component provider always returns the same instance of the component. The instance +///// is created when first required and is of the type passed in to the initializer. +//public final class ComponentSingletonProvider { +// private lazy var instance: Component = { +// componentType.init() +// }() +// +// private var componentType: ComponentInitializable.Type +// +// /// Initializer +// /// - Parameter type: The type of the single instance +// public init(type: ComponentInitializable.Type) { +// componentType = type +// } +//} +// +//extension ComponentSingletonProvider: ComponentProvider { +// /// Used to compare this provider with others. Any provider that returns the same single +// /// instance will be regarded as equivalent. +// /// - Returns: ObjectIdentifier of the single instance +// public var identifier: AnyHashable { +// ObjectIdentifier(instance) +// } +// +// /// Used to request a component from this provider +// /// - Returns: The single instance +// public func getComponent() -> Component { +// instance +// } +//} +// +//// MARK: - +// +///// This component provider calls a function to get the component instance. The function must +///// return a single component of the appropriate type. +//public final class DynamicComponentProvider { +// /// Wrapper for closure to make it hashable via ObjectIdentifier +// public final class Closure { +// let provideComponent: () -> C +// +// /// Initializer +// /// - Parameter provideComponent: Swift closure returning component of the appropriate type +// public init(provideComponent: @escaping () -> C) { +// self.provideComponent = provideComponent +// } +// } +// +// private let closure: Closure +// +// /// Initializer +// /// - Parameter closure: Instance of Closure class. A wrapper around closure that will +// /// return the component instance when called. +// public init(closure: Closure) { +// self.closure = closure +// } +//} +// +//extension DynamicComponentProvider: ComponentProvider { +// /// Used to compare this provider with others. Any provider that uses the function or method +// /// closure to provide the instance is regarded as equivalent. +// /// - Returns: ObjectIdentifier of closure +// public var identifier: AnyHashable { +// ObjectIdentifier(closure) +// } +// +// /// Used to request a component from this provider +// /// - Returns: The instance returned by calling the closure +// public func getComponent() -> Component { +// closure.provideComponent() +// } +//} +// +//// MARK: - +// +///// Represents a state for an EntityStateMachine. The state contains any number of ComponentProviders which +///// are used to add components to the entity when this state is entered. +//public class EntityState { +// internal var providers = [ComponentIdentifier: ComponentProvider]() +// +// public init() {} +// +// /// Add a new StateComponentMapping to this state. The mapping is a utility class that is used to +// /// map a component type to the provider that provides the component. +// /// - Parameter type: The type of component to be mapped +// /// - Returns: The component mapping to use when setting the provider for the component +// @discardableResult +// public func addMapping(for type: ComponentInitializable.Type) -> StateComponentMapping { +// StateComponentMapping(creatingState: self, type: type) +// } +// +// /// Get the ComponentProvider for a particular component type. +// /// - Parameter type: The type of component to get the provider for +// /// - Returns: The ComponentProvider +// public func provider(for type: ComponentInitializable.Type) -> ComponentProvider? { +// providers[type.identifier] +// } +// +// /// To determine whether this state has a provider for a specific component type. +// /// - Parameter type: The type of component to look for a provider for +// /// - Returns: true if there is a provider for the given type, false otherwise +// public func hasProvider(for type: ComponentInitializable.Type) -> Bool { +// providers[type.identifier] != nil +// } +//} +// +///// This extension provides ergonomic way to add component mapping and component +///// provider at once +//extension EntityState { +// /// Creates a mapping for the component type to a specific component instance. +// /// ComponentInstanceProvider is used for the mapping. +// /// - Parameter component: The component instance to use for the mapping +// /// - Returns: This EntityState, so more modifications can be applied +// @discardableResult +// @inline(__always) +// public func addInstance(_ component: C) -> Self { +// addMapping(for: C.self).withInstance(component) +// return self +// } +// +// /// Creates a mapping for the component type to new instances of the provided type. +// /// A ComponentTypeProvider is used for the mapping. +// /// - Parameter type: The type of components to be created by this mapping +// /// - Returns: This EntityState, so more modifications can be applied +// @inline(__always) +// @discardableResult +// public func addType(_ type: ComponentInitializable.Type) -> Self { +// addMapping(for: type).withType(type) +// return self +// } +// +// /// Creates a mapping for the component type to a single instance of the provided type. +// /// The instance is not created until it is first requested. +// /// A ComponentSingletonProvider is used for the mapping. +// /// - Parameter type: The type of the single instance to be created. +// /// - Returns: This EntityState, so more modifications can be applied +// @inline(__always) +// @discardableResult +// public func addSingleton(_ type: ComponentInitializable.Type) -> Self { +// addMapping(for: type).withSingleton(type) +// return self +// } +// +// /// Creates a mapping for the component type to a method call. +// /// A DynamicComponentProvider is used for the mapping. +// /// - Parameter closure: The Closure instance to return the component instance +// /// - Returns: This EntityState, so more modifications can be applied +// @inline(__always) +// @discardableResult +// public func addMethod(closure: DynamicComponentProvider.Closure) -> Self { +// addMapping(for: C.self).withMethod(closure) +// return self +// } +// +// /// Creates a mapping for the component type to any ComponentProvider. +// /// - Parameter type: The type of component to be mapped +// /// - Parameter provider: The component provider to use. +// /// - Returns: This EntityState, so more modifications can be applied. +// @inline(__always) +// @discardableResult +// public func addProvider(type: C.Type, provider: ComponentProvider) -> Self { +// addMapping(for: type).withProvider(provider) +// return self +// } +//} +// +//// MARK: - +// +///// Used by the EntityState class to create the mappings of components to providers via a fluent interface. +//public class StateComponentMapping { +// private var componentType: ComponentInitializable.Type +// private let creatingState: EntityState +// private var provider: ComponentProvider +// +// /// Used internally, the initializer creates a component mapping. The constructor +// /// creates a ComponentTypeProvider as the default mapping, which will be replaced +// /// by more specific mappings if other methods are called. +// /// - Parameter creatingState: The EntityState that the mapping will belong to +// /// - Parameter type: The component type for the mapping +// internal init(creatingState: EntityState, type: ComponentInitializable.Type) { +// self.creatingState = creatingState +// componentType = type +// provider = ComponentTypeProvider(type: type) +// setProvider(provider) +// } +// +// /// Creates a mapping for the component type to a specific component instance. A +// /// ComponentInstanceProvider is used for the mapping. +// /// - Parameter component: The component instance to use for the mapping +// /// - Returns: This ComponentMapping, so more modifications can be applied +// @discardableResult +// public func withInstance(_ component: Component) -> StateComponentMapping { +// setProvider(ComponentInstanceProvider(instance: component)) +// return self +// } +// +// /// Creates a mapping for the component type to new instances of the provided type. +// /// The type should be the same as or extend the type for this mapping. A ComponentTypeProvider +// /// is used for the mapping. +// /// - Parameter type: The type of components to be created by this mapping +// /// - Returns: This ComponentMapping, so more modifications can be applied +// @discardableResult +// public func withType(_ type: ComponentInitializable.Type) -> Self { +// setProvider(ComponentTypeProvider(type: type)) +// return self +// } +// +// /// Creates a mapping for the component type to a single instance of the provided type. +// /// The instance is not created until it is first requested. The type should be the same +// /// as or extend the type for this mapping. A ComponentSingletonProvider is used for +// /// the mapping. +// /// - Parameter type: The type of the single instance to be created. If omitted, the type of the +// /// mapping is used. +// /// - Returns: This ComponentMapping, so more modifications can be applied +// @discardableResult +// public func withSingleton(_ type: ComponentInitializable.Type?) -> Self { +// setProvider(ComponentSingletonProvider(type: type ?? componentType)) +// return self +// } +// +// /// Creates a mapping for the component type to a method call. A +// /// DynamicComponentProvider is used for the mapping. +// /// - Parameter closure: The Closure instance to return the component instance +// /// - Returns: This ComponentMapping, so more modifications can be applied +// @discardableResult +// public func withMethod(_ closure: DynamicComponentProvider.Closure) -> Self { +// setProvider(DynamicComponentProvider(closure: closure)) +// return self +// } +// +// /// Creates a mapping for the component type to any ComponentProvider. +// /// - Parameter provider: The component provider to use. +// /// - Returns: This ComponentMapping, so more modifications can be applied. +// @discardableResult +// public func withProvider(_ provider: ComponentProvider) -> Self { +// setProvider(provider) +// return self +// } +// +// /// Maps through to the addMapping method of the EntityState that this mapping belongs to +// /// so that a fluent interface can be used when configuring entity states. +// /// - Parameter type: The type of component to add a mapping to the state for +// /// - Returns: The new ComponentMapping for that type +// @discardableResult +// public func add(_ type: ComponentInitializable.Type) -> StateComponentMapping { +// creatingState.addMapping(for: type) +// } +// +// private func setProvider(_ provider: ComponentProvider) { +// self.provider = provider +// creatingState.providers[componentType.identifier] = provider +// } +//} +// +//// MARK: - +// +///// This is a state machine for an entity. The state machine manages a set of states, +///// each of which has a set of component providers. When the state machine changes the state, it removes +///// components associated with the previous state and adds components associated with the new state. +///// - Parameter StateIdentifier: Generic hashable state name type +//public class EntityStateMachine { +// private var states: [StateIdentifier: EntityState] +// +// /// The current state of the state machine. +// private var currentState: EntityState? +// +// /// The entity whose state machine this is +// public var entity: Entity +// +// /// Initializer. Creates an EntityStateMachine. +// public init(entity: Entity) { +// self.entity = entity +// states = [:] +// } +// +// /// Add a state to this state machine. +// /// - Parameter name: The name of this state - used to identify it later in the changeState method call. +// /// - Parameter state: The state. +// /// - Returns: This state machine, so methods can be chained. +// @discardableResult +// public func addState(name: StateIdentifier, state: EntityState) -> Self { +// states[name] = state +// return self +// } +// +// /// Create a new state in this state machine. +// /// - Parameter name: The name of the new state - used to identify it later in the changeState method call. +// /// - Returns: The new EntityState object that is the state. This will need to be configured with +// /// the appropriate component providers. +// public func createState(name: StateIdentifier) -> EntityState { +// let state = EntityState() +// states[name] = state +// return state +// } +// +// /// Change to a new state. The components from the old state will be removed and the components +// /// for the new state will be added. +// /// - Parameter name: The name of the state to change to. +// public func changeState(name: StateIdentifier) { +// guard let newState = states[name] else { +// assertionFailure("Entity state '\(name)' doesn't exist") +// return +// } +// +// if newState === currentState { +// return +// } +// +// var toAdd: [ComponentIdentifier: ComponentProvider] +// +// if let currentState = currentState { +// toAdd = .init() +// for (identifier, provider) in newState.providers { +// toAdd[identifier] = provider +// } +// +// for (identifier, _) in currentState.providers { +// if let other = toAdd[identifier], let current = currentState.providers[identifier], +// current.identifier == other.identifier { +// toAdd[identifier] = nil +// } else { +// entity.remove(identifier) +// } +// } +// } else { +// toAdd = newState.providers +// } +// +// for (_, provider) in toAdd { +// entity.assign(provider.getComponent()) +// } +// currentState = newState +// } +//} diff --git a/Sources/FirebladeECS/Nexus+Component.swift b/Sources/FirebladeECS/Nexus+Component.swift index 33f0819c..6bd988b0 100644 --- a/Sources/FirebladeECS/Nexus+Component.swift +++ b/Sources/FirebladeECS/Nexus+Component.swift @@ -65,7 +65,7 @@ extension Nexus { public final func get(unsafe entityId: EntityIdentifier) -> C where C: Component { let component: Component = get(unsafe: C.identifier, for: entityId) // components are guaranteed to be reference types so unsafeDowncast is applicable here - return unsafeDowncast(component, to: C.self) + return component as! C } @inlinable diff --git a/Tests/FirebladeECSTests/EntityTests.swift b/Tests/FirebladeECSTests/EntityTests.swift index 7b683dbe..ff084216 100644 --- a/Tests/FirebladeECSTests/EntityTests.swift +++ b/Tests/FirebladeECSTests/EntityTests.swift @@ -22,22 +22,22 @@ class EntityTests: XCTestCase { XCTAssertEqual(max.id, UInt32.max) } - func testAllComponentsOfEntity() { - let nexus = Nexus() - - let pos = Position(x: 1, y: 2) - let name = Name(name: "Hello") - let vel = Velocity(a: 1.234) - - let entity = nexus.createEntity() - entity.assign(pos) - entity.assign(name, vel) - - let expectedComponents: [Component] = [pos, name, vel] - let allComponents = Array(entity.makeComponentsIterator()) - - XCTAssertTrue(allComponents.elementsEqualUnordered(expectedComponents) { $0 === $1 }) - } +// func testAllComponentsOfEntity() { +// let nexus = Nexus() +// +// let pos = Position(x: 1, y: 2) +// let name = Name(name: "Hello") +// let vel = Velocity(a: 1.234) +// +// let entity = nexus.createEntity() +// entity.assign(pos) +// entity.assign(name, vel) +// +// let expectedComponents: [Component] = [pos, name, vel] +// let allComponents = Array(entity.makeComponentsIterator()) +// +// XCTAssertTrue(allComponents.elementsEqualUnordered(expectedComponents) { $0 == $1 }) +// } func testEntityEquality() { let nexus = Nexus() diff --git a/Tests/FirebladeECSTests/FSMTests.swift b/Tests/FirebladeECSTests/FSMTests.swift index e61e351b..9b891425 100644 --- a/Tests/FirebladeECSTests/FSMTests.swift +++ b/Tests/FirebladeECSTests/FSMTests.swift @@ -1,550 +1,550 @@ +//// +//// FSMTests.swift +//// FirebladeECSTests +//// +//// Created by Igor Kravchenko on 29.09.2020. +//// // -// FSMTests.swift -// FirebladeECSTests -// -// Created by Igor Kravchenko on 29.09.2020. -// - -import FirebladeECS -import XCTest - -class ComponentInstanceProviderTests: XCTestCase { - func testProviderReturnsTheInstance() { - let instance = MockComponent(value: .max) - let provider1 = ComponentInstanceProvider(instance: instance) - let providedComponent = provider1.getComponent() as? MockComponent - XCTAssertTrue(providedComponent === instance) - } - - func testProvidersWithSameInstanceHaveSameIdentifier() { - let instance = MockComponent(value: .max) - let provider1 = ComponentInstanceProvider(instance: instance) - let provider2 = ComponentInstanceProvider(instance: instance) - XCTAssertEqual(provider1.identifier, provider2.identifier) - } - - func testProvidersWithDifferentInstanceHaveDifferentIdentifier() { - let provider1 = ComponentInstanceProvider(instance: MockComponent(value: .max)) - let provider2 = ComponentInstanceProvider(instance: MockComponent(value: .max)) - XCTAssertNotEqual(provider1.identifier, provider2.identifier) - } - - class MockComponent: Component { - var value: Int - - init(value: Int) { - self.value = value - } - } -} - -// MARK: - - -class ComponentTypeProviderTests: XCTestCase { - func testProviderReturnsAnInstanceOfType() { - let provider = ComponentTypeProvider(type: MockComponent.self) - let component = provider.getComponent() as? MockComponent - XCTAssertNotNil(component) - } - - func testProviderReturnsNewInstanceEachTime() { - let provider = ComponentTypeProvider(type: MockComponent.self) - let component1 = provider.getComponent() as? MockComponent - let component2 = provider.getComponent() as? MockComponent - XCTAssertFalse(component1 === component2) - } - - func testProvidersWithSameTypeHaveSameIdentifier() { - let provider1 = ComponentTypeProvider(type: MockComponent.self) - let provider2 = ComponentTypeProvider(type: MockComponent.self) - XCTAssertEqual(provider1.identifier, provider2.identifier) - } - - func testProvidersWithDifferentTypeHaveDifferentIdentifier() { - let provider1 = ComponentTypeProvider(type: MockComponent.self) - let provider2 = ComponentTypeProvider(type: MockComponent2.self) - XCTAssertNotEqual(provider1.identifier, provider2.identifier) - } - - class MockComponent: Component, DefaultInitializable { - var value: String - - required init() { - value = "" - } - } - - class MockComponent2: Component, DefaultInitializable { - var value: Bool - - required init() { - value = false - } - } -} - -// MARK: - - -class ComponentSingletonProviderTests: XCTestCase { - func testProviderReturnsAnInstanceOfType() { - let provider = ComponentSingletonProvider(type: MockComponent.self) - let component = provider.getComponent() as? MockComponent - XCTAssertNotNil(component) - } - - func testProviderReturnsSameInstanceEachTime() { - let provider = ComponentSingletonProvider(type: MockComponent.self) - let component1 = provider.getComponent() as? MockComponent - let component2 = provider.getComponent() as? MockComponent - XCTAssertTrue(component1 === component2) - - } - - func testProvidersWithSameTypeHaveDifferentIdentifier() { - let provider1 = ComponentSingletonProvider(type: MockComponent.self) - let provider2 = ComponentSingletonProvider(type: MockComponent.self) - XCTAssertNotEqual(provider1.identifier, provider2.identifier) - } - - func testProvidersWithDifferentTypeHaveDifferentIdentifier() { - let provider1 = ComponentSingletonProvider(type: MockComponent.self) - let provider2 = ComponentSingletonProvider(type: MockComponent2.self) - XCTAssertNotEqual(provider1.identifier, provider2.identifier) - } - - class MockComponent: Component, DefaultInitializable { - var value: Int - - required init() { - value = 0 - } - } - - class MockComponent2: Component, DefaultInitializable { - var value: String - - required init() { - value = "" - } - } -} - -// MARK: - - -class DynamicComponentProviderTests: XCTestCase { - func testProviderReturnsTheInstance() { - let instance = MockComponent(value: 0) - let providerMethod = DynamicComponentProvider.Closure { instance } - let provider = DynamicComponentProvider(closure: providerMethod) - let component = provider.getComponent() as? MockComponent - XCTAssertTrue(component === instance) - } - - func testProvidersWithSameMethodHaveSameIdentifier() { - let instance = MockComponent(value: 0) - let providerMethod = DynamicComponentProvider.Closure { instance } - let provider1 = DynamicComponentProvider(closure: providerMethod) - let provider2 = DynamicComponentProvider(closure: providerMethod) - XCTAssertEqual(provider1.identifier, provider2.identifier) - } - - func testProvidersWithDifferentMethodsHaveDifferentIdentifier() { - let instance = MockComponent(value: 0) - let providerMethod1 = DynamicComponentProvider.Closure { instance } - let providerMethod2 = DynamicComponentProvider.Closure { instance } - let provider1 = DynamicComponentProvider(closure: providerMethod1) - let provider2 = DynamicComponentProvider(closure: providerMethod2) - XCTAssertNotEqual(provider1.identifier, provider2.identifier) - } - - class MockComponent: Component { - let value: Int - - init(value: Int) { - self.value = value - } - } -} - -// MARK: - - -@testable import class FirebladeECS.EntityState - -class EntityStateTests: XCTestCase { - private var state = EntityState() - - override func setUp() { - state = EntityState() - } - - override func tearDown() { - state = EntityState() - } - - func testAddMappingWithNoQualifierCreatesTypeProvider() { - state.addMapping(for: MockComponent.self) - let provider = state.providers[MockComponent.identifier] - XCTAssertNotNil(provider) - XCTAssertTrue(provider is ComponentTypeProvider?) - XCTAssertTrue(provider?.getComponent() is MockComponent?) - } - - func testAddMappingWithTypeQualifierCreatesTypeProvider() { - state.addMapping(for: MockComponent.self).withType(MockComponent2.self) - let provider = state.providers[MockComponent.identifier] - XCTAssertNotNil(provider) - XCTAssertTrue(provider is ComponentTypeProvider?) - XCTAssertTrue(provider?.getComponent() is MockComponent2?) - } - - func testAddMappingWithInstanceQualifierCreatesInstanceProvider() { - let component = MockComponent() - state.addMapping(for: MockComponent.self).withInstance(component) - let provider = state.providers[MockComponent.identifier] - XCTAssertTrue(provider is ComponentInstanceProvider?) - XCTAssertTrue(provider?.getComponent() === component) - } - - func testAddMappingWithSingletonQualifierCreatesSingletonProvider() { - state.addMapping(for: MockComponent.self).withSingleton(MockComponent.self) - let provider = state.providers[MockComponent.identifier] - XCTAssertTrue(provider is ComponentSingletonProvider?) - XCTAssertTrue(provider?.getComponent() is MockComponent?) - } - - func testAddMappingWithMethodQualifierCreatesDynamicProvider() { - let dynamickProvider = DynamicComponentProvider.Closure { - MockComponent() - } - - state.addMapping(for: MockComponent.self).withMethod(dynamickProvider) - let provider = state.providers[MockComponent.identifier] - XCTAssertNotNil(provider) - XCTAssertTrue(provider is DynamicComponentProvider?) - XCTAssertTrue(provider?.getComponent() is MockComponent) - } - - func testProviderForTypeReturnsTypeProviderByDefault() { - state.addMapping(for: MockComponent.self) - let provider = state.provider(for: MockComponent.self) - XCTAssertNotNil(provider) - XCTAssertTrue(provider is ComponentTypeProvider?) - } - - func testProviderForTypeReturnsInstanceProvider() { - let component = MockComponent() - state.addMapping(for: MockComponent.self).withInstance(component) - let provider = state.provider(for: MockComponent.self) - XCTAssertNotNil(provider) - XCTAssertTrue(provider is ComponentInstanceProvider?) - } - - func testProviderForTypeReturnsSingletonProvider() { - state.addMapping(for: MockComponent.self).withSingleton(MockComponent.self) - let provider = state.provider(for: MockComponent.self) - XCTAssertNotNil(provider) - XCTAssertTrue(provider is ComponentSingletonProvider?) - } - - func testProviderForTypeReturnsDynamicProvider() { - state.addMapping(for: MockComponent.self).withMethod(.init { MockComponent() }) - let provider = state.provider(for: MockComponent.self) - XCTAssertNotNil(provider) - XCTAssertTrue(provider is DynamicComponentProvider?) - } - - func testProviderForTypeReturnsTypeProvider() { - state.addMapping(for: MockComponent.self).withType(MockComponent.self) - let provider = state.provider(for: MockComponent.self) - XCTAssertNotNil(provider) - XCTAssertTrue(provider is ComponentTypeProvider?) - } - - func testProviderForTypeReturnsPassedProvider() { - let singletonProvider = ComponentSingletonProvider(type: MockComponent.self) - state.addMapping(for: MockComponent.self).withProvider(singletonProvider) - let provider = state.provider(for: MockComponent.self) as? ComponentSingletonProvider - XCTAssertNotNil(provider) - XCTAssertTrue(provider === singletonProvider) - } - - func testHasProviderReturnsFalseForNotCreatedProvider() { - XCTAssertFalse(state.hasProvider(for: MockComponent.self)) - } - - func testHasProviderReturnsTrueForCreatedProvider() { - state.addMapping(for: MockComponent.self) - XCTAssertTrue(state.hasProvider(for: MockComponent.self)) - } - - func testAddInstanceCreatesMappingAndSetsInstanceProviderForInstanceType() { - let component = MockComponent() - state.addInstance(component) - XCTAssertTrue(state.provider(for: MockComponent.self) is ComponentInstanceProvider?) - XCTAssert(state.provider(for: MockComponent.self)?.getComponent() === component) - } - - func testAddTypeCreatesMappingAndSetsTypeProviderForType() { - state.addType(MockComponent.self) - XCTAssertTrue(state.provider(for: MockComponent.self) is ComponentTypeProvider?) - XCTAssertNotNil(state.provider(for: MockComponent.self)?.getComponent()) - XCTAssertTrue(state.provider(for: MockComponent.self)?.getComponent() is MockComponent?) - } - - func testAddSingletonCreatesMappingAndSetsSingletonProviderForType() { - state.addSingleton(MockComponent.self) - XCTAssertTrue(state.provider(for: MockComponent.self) is ComponentSingletonProvider?) - XCTAssertNotNil(state.provider(for: MockComponent.self)?.getComponent()) - XCTAssertTrue(state.provider(for: MockComponent.self)?.getComponent() is MockComponent?) - } - - func testAddMethodCreatesMappingAndSetsDynamicProviderForType() { - let component = MockComponent() - state.addMethod(closure: .init { component }) - XCTAssertTrue(state.provider(for: MockComponent.self) is DynamicComponentProvider?) - XCTAssertTrue(state.provider(for: MockComponent.self)?.getComponent() === component) - } - - func testAddProviderCreatesMappingAndSetsProvider() { - let provider = ComponentSingletonProvider(type: MockComponent.self) - state.addProvider(type: MockComponent.self, provider: provider) - XCTAssert(state.provider(for: MockComponent.self) is ComponentSingletonProvider?) - XCTAssertNotNil(state.provider(for: MockComponent.self)) - } - - class MockComponent: ComponentInitializable { - let value: Int - - init(value: Int) { - self.value = value - } - - required init() { - value = 0 - } - } - - class MockComponent2: MockComponent {} -} - -// MARK: - - -class EntityStateMachineTests: XCTestCase { - var nexus = Nexus() - var fsm = EntityStateMachine(entity: .init(nexus: .init(), id: .invalid)) - var entity = Entity(nexus: .init(), id: .init(rawValue: 1)) - - override func setUp() { - nexus = Nexus() - entity = nexus.createEntity() - fsm = EntityStateMachine(entity: entity) - } - - func testEnterStateAddsStatesComponents() { - let state = EntityState() - let component = MockComponent() - state.addMapping(for: MockComponent.self).withInstance(component) - fsm.addState(name: "test", state: state) - fsm.changeState(name: "test") - XCTAssertTrue(entity.get(component: MockComponent.self) === component) - } - - func testEnterSecondStateAddsSecondStatesComponents() { - let state1 = EntityState() - let component1 = MockComponent() - state1.addMapping(for: MockComponent.self).withInstance(component1) - fsm.addState(name: "test1", state: state1) - - let state2 = EntityState() - let component2 = MockComponent2() - state2.addMapping(for: MockComponent2.self).withInstance(component2) - fsm.addState(name: "test2", state: state2) - fsm.changeState(name: "test2") - - XCTAssertTrue(entity.get(component: MockComponent2.self) === component2) - } - - func testEnterSecondStateRemovesFirstStatesComponents() { - let state1 = EntityState() - let component1 = MockComponent() - state1.addMapping(for: MockComponent.self).withInstance(component1) - fsm.addState(name: "test1", state: state1) - fsm.changeState(name: "test1") - - let state2 = EntityState() - let component2 = MockComponent2() - state2.addMapping(for: MockComponent2.self).withInstance(component2) - fsm.addState(name: "test2", state: state2) - fsm.changeState(name: "test2") - - XCTAssertFalse(entity.has(MockComponent.self)) - } - - func testEnterSecondStateDoesNotRemoveOverlappingComponents() { - class EventDelegate: NexusEventDelegate { - init() {} - - func nexusEvent(_ event: NexusEvent) { - XCTAssertFalse(event is ComponentRemoved, "Component was removed when it shouldn't have been.") - } - - func nexusNonFatalError(_ message: String) {} - } - let delgate = EventDelegate() - nexus.delegate = delgate - let state1 = EntityState() - let component1 = MockComponent() - state1.addMapping(for: MockComponent.self).withInstance(component1) - fsm.addState(name: "test1", state: state1) - fsm.changeState(name: "test1") - - let state2 = EntityState() - let component2 = MockComponent2() - state2.addMapping(for: MockComponent.self).withInstance(component1) - state2.addMapping(for: MockComponent2.self).withInstance(component2) - fsm.addState(name: "test2", state: state2) - fsm.changeState(name: "test2") - - XCTAssertTrue(entity.get(component: MockComponent.self) === component1) - } - - func testEnterSecondStateRemovesDifferentComponentsOfSameType() { - let state1 = EntityState() - let component1 = MockComponent() - state1.addMapping(for: MockComponent.self).withInstance(component1) - fsm.addState(name: "test1", state: state1) - fsm.changeState(name: "test1") - - let state2 = EntityState() - let component3 = MockComponent() - let component2 = MockComponent2() - state2.addMapping(for: MockComponent.self).withInstance(component3) - state2.addMapping(for: MockComponent2.self).withInstance(component2) - fsm.addState(name: "test2", state: state2) - fsm.changeState(name: "test2") - - XCTAssertTrue(entity.get(component: MockComponent.self) === component3) - } - - func testCreateStateAddsState() { - let state = fsm.createState(name: "test") - let component = MockComponent() - state.addMapping(for: MockComponent.self).withInstance(component) - fsm.changeState(name: "test") - XCTAssertTrue(entity.get(component: MockComponent.self) === component) - } - - func testCreateStateDoesNotChangeState() { - let state = fsm.createState(name: "test") - let component = MockComponent() - state.addMapping(for: MockComponent.self).withInstance(component) - XCTAssertNil(entity.get(component: MockComponent.self)) - } - - func testCallChangeStateWithSameNameLeavesEntityComponentsIntact() { - let state = fsm.createState(name: "test") - let component1 = MockComponent() - let component2 = MockComponent2() - state.addMapping(for: MockComponent.self).withInstance(component1) - state.addMapping(for: MockComponent2.self).withInstance(component2) - let name = "test" - fsm.changeState(name: name) - XCTAssertTrue(entity.get(component: MockComponent.self) === component1) - XCTAssertTrue(entity.get(component: MockComponent2.self) === component2) - fsm.changeState(name: name) - XCTAssertTrue(entity.get(component: MockComponent.self) === component1) - XCTAssertTrue(entity.get(component: MockComponent2.self) === component2) - } - - func testGetsDeinitedWhileBeingStronglyReferencedByComponentAssignedToEntity() { - class Marker: Component { - let fsm: EntityStateMachine - init(fsm: EntityStateMachine) { - self.fsm = fsm - } - } - - let nexus = Nexus() - var entity = nexus.createEntity() - var markerComponent = Marker(fsm: EntityStateMachine(entity: entity)) - entity.assign(markerComponent) - weak var weakMarker = markerComponent - weak var weakFsm = markerComponent.fsm - nexus.destroy(entity: entity) - entity = nexus.createEntity() - markerComponent = .init(fsm: .init(entity: entity)) - XCTAssertNil(weakMarker) - XCTAssertNil(weakFsm) - } - - class MockComponent: ComponentInitializable { - let value: Int - - init(value: Int) { - self.value = value - } - - required init() { - value = 0 - } - } - - class MockComponent2: ComponentInitializable { - let value: String - - init(value: String) { - self.value = value - } - - required init() { - self.value = "" - } - } -} - -// MARK: - - -class StateComponentMappingTests: XCTestCase { - func testAddReturnsSameMappingForSameComponentType() { - let state = EntityState() - let mapping = state.addMapping(for: MockComponent.self) - XCTAssertFalse(mapping === mapping.add(MockComponent.self)) - } - - func testAddReturnsSameMappingForDifferentComponentTypes() { - let state = EntityState() - let mapping = state.addMapping(for: MockComponent.self) - XCTAssertFalse(mapping === mapping.add(MockComponent2.self)) - } - - func testAddAddsProviderToState() { - let state = EntityState() - let mapping = state.addMapping(for: MockComponent.self) - mapping.add(MockComponent2.self) - XCTAssertTrue(state.hasProvider(for: MockComponent.self)) - } - - class MockComponent: ComponentInitializable { - let value: Int - - init(value: Int) { - self.value = value - } - - required init() { - self.value = 0 - } - } - - class MockComponent2: ComponentInitializable { - let value: String - - init(value: String) { - self.value = value - } - - required init() { - self.value = "" - } - } -} +//import FirebladeECS +//import XCTest +// +//class ComponentInstanceProviderTests: XCTestCase { +// func testProviderReturnsTheInstance() { +// let instance = MockComponent(value: .max) +// let provider1 = ComponentInstanceProvider(instance: instance) +// let providedComponent = provider1.getComponent() as? MockComponent +// XCTAssertTrue(providedComponent === instance) +// } +// +// func testProvidersWithSameInstanceHaveSameIdentifier() { +// let instance = MockComponent(value: .max) +// let provider1 = ComponentInstanceProvider(instance: instance) +// let provider2 = ComponentInstanceProvider(instance: instance) +// XCTAssertEqual(provider1.identifier, provider2.identifier) +// } +// +// func testProvidersWithDifferentInstanceHaveDifferentIdentifier() { +// let provider1 = ComponentInstanceProvider(instance: MockComponent(value: .max)) +// let provider2 = ComponentInstanceProvider(instance: MockComponent(value: .max)) +// XCTAssertNotEqual(provider1.identifier, provider2.identifier) +// } +// +// class MockComponent: Component { +// var value: Int +// +// init(value: Int) { +// self.value = value +// } +// } +//} +// +//// MARK: - +// +//class ComponentTypeProviderTests: XCTestCase { +// func testProviderReturnsAnInstanceOfType() { +// let provider = ComponentTypeProvider(type: MockComponent.self) +// let component = provider.getComponent() as? MockComponent +// XCTAssertNotNil(component) +// } +// +// func testProviderReturnsNewInstanceEachTime() { +// let provider = ComponentTypeProvider(type: MockComponent.self) +// let component1 = provider.getComponent() as? MockComponent +// let component2 = provider.getComponent() as? MockComponent +// XCTAssertFalse(component1 === component2) +// } +// +// func testProvidersWithSameTypeHaveSameIdentifier() { +// let provider1 = ComponentTypeProvider(type: MockComponent.self) +// let provider2 = ComponentTypeProvider(type: MockComponent.self) +// XCTAssertEqual(provider1.identifier, provider2.identifier) +// } +// +// func testProvidersWithDifferentTypeHaveDifferentIdentifier() { +// let provider1 = ComponentTypeProvider(type: MockComponent.self) +// let provider2 = ComponentTypeProvider(type: MockComponent2.self) +// XCTAssertNotEqual(provider1.identifier, provider2.identifier) +// } +// +// class MockComponent: Component, DefaultInitializable { +// var value: String +// +// required init() { +// value = "" +// } +// } +// +// class MockComponent2: Component, DefaultInitializable { +// var value: Bool +// +// required init() { +// value = false +// } +// } +//} +// +//// MARK: - +// +//class ComponentSingletonProviderTests: XCTestCase { +// func testProviderReturnsAnInstanceOfType() { +// let provider = ComponentSingletonProvider(type: MockComponent.self) +// let component = provider.getComponent() as? MockComponent +// XCTAssertNotNil(component) +// } +// +// func testProviderReturnsSameInstanceEachTime() { +// let provider = ComponentSingletonProvider(type: MockComponent.self) +// let component1 = provider.getComponent() as? MockComponent +// let component2 = provider.getComponent() as? MockComponent +// XCTAssertTrue(component1 === component2) +// +// } +// +// func testProvidersWithSameTypeHaveDifferentIdentifier() { +// let provider1 = ComponentSingletonProvider(type: MockComponent.self) +// let provider2 = ComponentSingletonProvider(type: MockComponent.self) +// XCTAssertNotEqual(provider1.identifier, provider2.identifier) +// } +// +// func testProvidersWithDifferentTypeHaveDifferentIdentifier() { +// let provider1 = ComponentSingletonProvider(type: MockComponent.self) +// let provider2 = ComponentSingletonProvider(type: MockComponent2.self) +// XCTAssertNotEqual(provider1.identifier, provider2.identifier) +// } +// +// class MockComponent: Component, DefaultInitializable { +// var value: Int +// +// required init() { +// value = 0 +// } +// } +// +// class MockComponent2: Component, DefaultInitializable { +// var value: String +// +// required init() { +// value = "" +// } +// } +//} +// +//// MARK: - +// +//class DynamicComponentProviderTests: XCTestCase { +// func testProviderReturnsTheInstance() { +// let instance = MockComponent(value: 0) +// let providerMethod = DynamicComponentProvider.Closure { instance } +// let provider = DynamicComponentProvider(closure: providerMethod) +// let component = provider.getComponent() as? MockComponent +// XCTAssertTrue(component === instance) +// } +// +// func testProvidersWithSameMethodHaveSameIdentifier() { +// let instance = MockComponent(value: 0) +// let providerMethod = DynamicComponentProvider.Closure { instance } +// let provider1 = DynamicComponentProvider(closure: providerMethod) +// let provider2 = DynamicComponentProvider(closure: providerMethod) +// XCTAssertEqual(provider1.identifier, provider2.identifier) +// } +// +// func testProvidersWithDifferentMethodsHaveDifferentIdentifier() { +// let instance = MockComponent(value: 0) +// let providerMethod1 = DynamicComponentProvider.Closure { instance } +// let providerMethod2 = DynamicComponentProvider.Closure { instance } +// let provider1 = DynamicComponentProvider(closure: providerMethod1) +// let provider2 = DynamicComponentProvider(closure: providerMethod2) +// XCTAssertNotEqual(provider1.identifier, provider2.identifier) +// } +// +// class MockComponent: Component { +// let value: Int +// +// init(value: Int) { +// self.value = value +// } +// } +//} +// +//// MARK: - +// +//@testable import class FirebladeECS.EntityState +// +//class EntityStateTests: XCTestCase { +// private var state = EntityState() +// +// override func setUp() { +// state = EntityState() +// } +// +// override func tearDown() { +// state = EntityState() +// } +// +// func testAddMappingWithNoQualifierCreatesTypeProvider() { +// state.addMapping(for: MockComponent.self) +// let provider = state.providers[MockComponent.identifier] +// XCTAssertNotNil(provider) +// XCTAssertTrue(provider is ComponentTypeProvider?) +// XCTAssertTrue(provider?.getComponent() is MockComponent?) +// } +// +// func testAddMappingWithTypeQualifierCreatesTypeProvider() { +// state.addMapping(for: MockComponent.self).withType(MockComponent2.self) +// let provider = state.providers[MockComponent.identifier] +// XCTAssertNotNil(provider) +// XCTAssertTrue(provider is ComponentTypeProvider?) +// XCTAssertTrue(provider?.getComponent() is MockComponent2?) +// } +// +// func testAddMappingWithInstanceQualifierCreatesInstanceProvider() { +// let component = MockComponent() +// state.addMapping(for: MockComponent.self).withInstance(component) +// let provider = state.providers[MockComponent.identifier] +// XCTAssertTrue(provider is ComponentInstanceProvider?) +// XCTAssertTrue(provider?.getComponent() === component) +// } +// +// func testAddMappingWithSingletonQualifierCreatesSingletonProvider() { +// state.addMapping(for: MockComponent.self).withSingleton(MockComponent.self) +// let provider = state.providers[MockComponent.identifier] +// XCTAssertTrue(provider is ComponentSingletonProvider?) +// XCTAssertTrue(provider?.getComponent() is MockComponent?) +// } +// +// func testAddMappingWithMethodQualifierCreatesDynamicProvider() { +// let dynamickProvider = DynamicComponentProvider.Closure { +// MockComponent() +// } +// +// state.addMapping(for: MockComponent.self).withMethod(dynamickProvider) +// let provider = state.providers[MockComponent.identifier] +// XCTAssertNotNil(provider) +// XCTAssertTrue(provider is DynamicComponentProvider?) +// XCTAssertTrue(provider?.getComponent() is MockComponent) +// } +// +// func testProviderForTypeReturnsTypeProviderByDefault() { +// state.addMapping(for: MockComponent.self) +// let provider = state.provider(for: MockComponent.self) +// XCTAssertNotNil(provider) +// XCTAssertTrue(provider is ComponentTypeProvider?) +// } +// +// func testProviderForTypeReturnsInstanceProvider() { +// let component = MockComponent() +// state.addMapping(for: MockComponent.self).withInstance(component) +// let provider = state.provider(for: MockComponent.self) +// XCTAssertNotNil(provider) +// XCTAssertTrue(provider is ComponentInstanceProvider?) +// } +// +// func testProviderForTypeReturnsSingletonProvider() { +// state.addMapping(for: MockComponent.self).withSingleton(MockComponent.self) +// let provider = state.provider(for: MockComponent.self) +// XCTAssertNotNil(provider) +// XCTAssertTrue(provider is ComponentSingletonProvider?) +// } +// +// func testProviderForTypeReturnsDynamicProvider() { +// state.addMapping(for: MockComponent.self).withMethod(.init { MockComponent() }) +// let provider = state.provider(for: MockComponent.self) +// XCTAssertNotNil(provider) +// XCTAssertTrue(provider is DynamicComponentProvider?) +// } +// +// func testProviderForTypeReturnsTypeProvider() { +// state.addMapping(for: MockComponent.self).withType(MockComponent.self) +// let provider = state.provider(for: MockComponent.self) +// XCTAssertNotNil(provider) +// XCTAssertTrue(provider is ComponentTypeProvider?) +// } +// +// func testProviderForTypeReturnsPassedProvider() { +// let singletonProvider = ComponentSingletonProvider(type: MockComponent.self) +// state.addMapping(for: MockComponent.self).withProvider(singletonProvider) +// let provider = state.provider(for: MockComponent.self) as? ComponentSingletonProvider +// XCTAssertNotNil(provider) +// XCTAssertTrue(provider === singletonProvider) +// } +// +// func testHasProviderReturnsFalseForNotCreatedProvider() { +// XCTAssertFalse(state.hasProvider(for: MockComponent.self)) +// } +// +// func testHasProviderReturnsTrueForCreatedProvider() { +// state.addMapping(for: MockComponent.self) +// XCTAssertTrue(state.hasProvider(for: MockComponent.self)) +// } +// +// func testAddInstanceCreatesMappingAndSetsInstanceProviderForInstanceType() { +// let component = MockComponent() +// state.addInstance(component) +// XCTAssertTrue(state.provider(for: MockComponent.self) is ComponentInstanceProvider?) +// XCTAssert(state.provider(for: MockComponent.self)?.getComponent() === component) +// } +// +// func testAddTypeCreatesMappingAndSetsTypeProviderForType() { +// state.addType(MockComponent.self) +// XCTAssertTrue(state.provider(for: MockComponent.self) is ComponentTypeProvider?) +// XCTAssertNotNil(state.provider(for: MockComponent.self)?.getComponent()) +// XCTAssertTrue(state.provider(for: MockComponent.self)?.getComponent() is MockComponent?) +// } +// +// func testAddSingletonCreatesMappingAndSetsSingletonProviderForType() { +// state.addSingleton(MockComponent.self) +// XCTAssertTrue(state.provider(for: MockComponent.self) is ComponentSingletonProvider?) +// XCTAssertNotNil(state.provider(for: MockComponent.self)?.getComponent()) +// XCTAssertTrue(state.provider(for: MockComponent.self)?.getComponent() is MockComponent?) +// } +// +// func testAddMethodCreatesMappingAndSetsDynamicProviderForType() { +// let component = MockComponent() +// state.addMethod(closure: .init { component }) +// XCTAssertTrue(state.provider(for: MockComponent.self) is DynamicComponentProvider?) +// XCTAssertTrue(state.provider(for: MockComponent.self)?.getComponent() === component) +// } +// +// func testAddProviderCreatesMappingAndSetsProvider() { +// let provider = ComponentSingletonProvider(type: MockComponent.self) +// state.addProvider(type: MockComponent.self, provider: provider) +// XCTAssert(state.provider(for: MockComponent.self) is ComponentSingletonProvider?) +// XCTAssertNotNil(state.provider(for: MockComponent.self)) +// } +// +// class MockComponent: ComponentInitializable { +// let value: Int +// +// init(value: Int) { +// self.value = value +// } +// +// required init() { +// value = 0 +// } +// } +// +// class MockComponent2: MockComponent {} +//} +// +//// MARK: - +// +//class EntityStateMachineTests: XCTestCase { +// var nexus = Nexus() +// var fsm = EntityStateMachine(entity: .init(nexus: .init(), id: .invalid)) +// var entity = Entity(nexus: .init(), id: .init(rawValue: 1)) +// +// override func setUp() { +// nexus = Nexus() +// entity = nexus.createEntity() +// fsm = EntityStateMachine(entity: entity) +// } +// +// func testEnterStateAddsStatesComponents() { +// let state = EntityState() +// let component = MockComponent() +// state.addMapping(for: MockComponent.self).withInstance(component) +// fsm.addState(name: "test", state: state) +// fsm.changeState(name: "test") +// XCTAssertTrue(entity.get(component: MockComponent.self) === component) +// } +// +// func testEnterSecondStateAddsSecondStatesComponents() { +// let state1 = EntityState() +// let component1 = MockComponent() +// state1.addMapping(for: MockComponent.self).withInstance(component1) +// fsm.addState(name: "test1", state: state1) +// +// let state2 = EntityState() +// let component2 = MockComponent2() +// state2.addMapping(for: MockComponent2.self).withInstance(component2) +// fsm.addState(name: "test2", state: state2) +// fsm.changeState(name: "test2") +// +// XCTAssertTrue(entity.get(component: MockComponent2.self) === component2) +// } +// +// func testEnterSecondStateRemovesFirstStatesComponents() { +// let state1 = EntityState() +// let component1 = MockComponent() +// state1.addMapping(for: MockComponent.self).withInstance(component1) +// fsm.addState(name: "test1", state: state1) +// fsm.changeState(name: "test1") +// +// let state2 = EntityState() +// let component2 = MockComponent2() +// state2.addMapping(for: MockComponent2.self).withInstance(component2) +// fsm.addState(name: "test2", state: state2) +// fsm.changeState(name: "test2") +// +// XCTAssertFalse(entity.has(MockComponent.self)) +// } +// +// func testEnterSecondStateDoesNotRemoveOverlappingComponents() { +// class EventDelegate: NexusEventDelegate { +// init() {} +// +// func nexusEvent(_ event: NexusEvent) { +// XCTAssertFalse(event is ComponentRemoved, "Component was removed when it shouldn't have been.") +// } +// +// func nexusNonFatalError(_ message: String) {} +// } +// let delgate = EventDelegate() +// nexus.delegate = delgate +// let state1 = EntityState() +// let component1 = MockComponent() +// state1.addMapping(for: MockComponent.self).withInstance(component1) +// fsm.addState(name: "test1", state: state1) +// fsm.changeState(name: "test1") +// +// let state2 = EntityState() +// let component2 = MockComponent2() +// state2.addMapping(for: MockComponent.self).withInstance(component1) +// state2.addMapping(for: MockComponent2.self).withInstance(component2) +// fsm.addState(name: "test2", state: state2) +// fsm.changeState(name: "test2") +// +// XCTAssertTrue(entity.get(component: MockComponent.self) === component1) +// } +// +// func testEnterSecondStateRemovesDifferentComponentsOfSameType() { +// let state1 = EntityState() +// let component1 = MockComponent() +// state1.addMapping(for: MockComponent.self).withInstance(component1) +// fsm.addState(name: "test1", state: state1) +// fsm.changeState(name: "test1") +// +// let state2 = EntityState() +// let component3 = MockComponent() +// let component2 = MockComponent2() +// state2.addMapping(for: MockComponent.self).withInstance(component3) +// state2.addMapping(for: MockComponent2.self).withInstance(component2) +// fsm.addState(name: "test2", state: state2) +// fsm.changeState(name: "test2") +// +// XCTAssertTrue(entity.get(component: MockComponent.self) === component3) +// } +// +// func testCreateStateAddsState() { +// let state = fsm.createState(name: "test") +// let component = MockComponent() +// state.addMapping(for: MockComponent.self).withInstance(component) +// fsm.changeState(name: "test") +// XCTAssertTrue(entity.get(component: MockComponent.self) === component) +// } +// +// func testCreateStateDoesNotChangeState() { +// let state = fsm.createState(name: "test") +// let component = MockComponent() +// state.addMapping(for: MockComponent.self).withInstance(component) +// XCTAssertNil(entity.get(component: MockComponent.self)) +// } +// +// func testCallChangeStateWithSameNameLeavesEntityComponentsIntact() { +// let state = fsm.createState(name: "test") +// let component1 = MockComponent() +// let component2 = MockComponent2() +// state.addMapping(for: MockComponent.self).withInstance(component1) +// state.addMapping(for: MockComponent2.self).withInstance(component2) +// let name = "test" +// fsm.changeState(name: name) +// XCTAssertTrue(entity.get(component: MockComponent.self) === component1) +// XCTAssertTrue(entity.get(component: MockComponent2.self) === component2) +// fsm.changeState(name: name) +// XCTAssertTrue(entity.get(component: MockComponent.self) === component1) +// XCTAssertTrue(entity.get(component: MockComponent2.self) === component2) +// } +// +// func testGetsDeinitedWhileBeingStronglyReferencedByComponentAssignedToEntity() { +// class Marker: Component { +// let fsm: EntityStateMachine +// init(fsm: EntityStateMachine) { +// self.fsm = fsm +// } +// } +// +// let nexus = Nexus() +// var entity = nexus.createEntity() +// var markerComponent = Marker(fsm: EntityStateMachine(entity: entity)) +// entity.assign(markerComponent) +// weak var weakMarker = markerComponent +// weak var weakFsm = markerComponent.fsm +// nexus.destroy(entity: entity) +// entity = nexus.createEntity() +// markerComponent = .init(fsm: .init(entity: entity)) +// XCTAssertNil(weakMarker) +// XCTAssertNil(weakFsm) +// } +// +// class MockComponent: ComponentInitializable { +// let value: Int +// +// init(value: Int) { +// self.value = value +// } +// +// required init() { +// value = 0 +// } +// } +// +// class MockComponent2: ComponentInitializable { +// let value: String +// +// init(value: String) { +// self.value = value +// } +// +// required init() { +// self.value = "" +// } +// } +//} +// +//// MARK: - +// +//class StateComponentMappingTests: XCTestCase { +// func testAddReturnsSameMappingForSameComponentType() { +// let state = EntityState() +// let mapping = state.addMapping(for: MockComponent.self) +// XCTAssertFalse(mapping === mapping.add(MockComponent.self)) +// } +// +// func testAddReturnsSameMappingForDifferentComponentTypes() { +// let state = EntityState() +// let mapping = state.addMapping(for: MockComponent.self) +// XCTAssertFalse(mapping === mapping.add(MockComponent2.self)) +// } +// +// func testAddAddsProviderToState() { +// let state = EntityState() +// let mapping = state.addMapping(for: MockComponent.self) +// mapping.add(MockComponent2.self) +// XCTAssertTrue(state.hasProvider(for: MockComponent.self)) +// } +// +// class MockComponent: ComponentInitializable { +// let value: Int +// +// init(value: Int) { +// self.value = value +// } +// +// required init() { +// self.value = 0 +// } +// } +// +// class MockComponent2: ComponentInitializable { +// let value: String +// +// init(value: String) { +// self.value = value +// } +// +// required init() { +// self.value = "" +// } +// } +//} From 4cd8a1a8652d9dfddbc36c4b22e4e6b78b20b03a Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Fri, 11 Oct 2024 09:43:36 +0200 Subject: [PATCH 3/3] Update project with current master --- .codecov.yml | 3 +- .github/workflows/ci-linux.yml | 40 +- .github/workflows/ci-macos.yml | 56 ++- .github/workflows/ci-wasm.yml | 4 +- .github/workflows/ci-windows.yml | 53 +- .github/workflows/documentation.yml | 4 +- .gitlab-ci.yml | 25 - .swift-version | 1 + .swiftformat | 13 + .swiftlint.yml | 23 +- Benchmarks/Benchmarks/ECSBenchmark/Base.swift | 85 ++++ .../ECSBenchmark/OneDimensionBenchmarks.swift | 198 ++++++++ Benchmarks/Package.swift | 28 ++ Benchmarks/README.md | 22 + Makefile | 126 +++-- Mintfile | 3 + Package.swift | 8 +- README.md | 6 +- Sources/FirebladeECS/CodingStrategy.swift | 2 +- .../FirebladeECS/ComponentIdentifier.swift | 10 +- Sources/FirebladeECS/Entity.swift | 23 +- Sources/FirebladeECS/EntityIdentifier.swift | 6 +- .../EntityIdentifierGenerator.swift | 8 +- Sources/FirebladeECS/FSM.swift | 17 +- Sources/FirebladeECS/Family+Coding.swift | 4 +- Sources/FirebladeECS/Family.swift | 26 +- .../FirebladeECS/FamilyMemberBuilder.swift | 8 +- Sources/FirebladeECS/FamilyTraitSet.swift | 2 +- .../FirebladeECS/Foundation+Extensions.swift | 6 +- .../Generated/Family.generated.swift | 98 ++-- Sources/FirebladeECS/Hashing.swift | 17 +- .../FirebladeECS/ManagedContiguousArray.swift | 4 +- Sources/FirebladeECS/Nexus+Component.swift | 6 +- .../Nexus+ComponentsBuilder.swift | 16 +- Sources/FirebladeECS/Nexus+Entity.swift | 12 +- Sources/FirebladeECS/Nexus+Internal.swift | 6 +- Sources/FirebladeECS/Nexus.swift | 17 +- Sources/FirebladeECS/NexusEvent.swift | 2 +- Sources/FirebladeECS/Single.swift | 4 +- Sources/FirebladeECS/UnorderedSparseSet.swift | 22 +- .../HashingPerformanceTests.swift | 4 + .../TypeIdentifierPerformanceTests.swift | 6 +- .../XCTestManifests.swift | 70 --- .../Generated/FamilyTests.generated.swift | 3 +- Tests/FirebladeECSTests/XCTestManifests.swift | 454 ------------------ Tests/LinuxMain.swift | 10 - renovate.json | 13 + 47 files changed, 691 insertions(+), 883 deletions(-) delete mode 100644 .gitlab-ci.yml create mode 100644 .swift-version create mode 100644 .swiftformat create mode 100644 Benchmarks/Benchmarks/ECSBenchmark/Base.swift create mode 100644 Benchmarks/Benchmarks/ECSBenchmark/OneDimensionBenchmarks.swift create mode 100644 Benchmarks/Package.swift create mode 100644 Benchmarks/README.md create mode 100644 Mintfile delete mode 100644 Tests/FirebladeECSPerformanceTests/XCTestManifests.swift delete mode 100644 Tests/FirebladeECSTests/XCTestManifests.swift delete mode 100644 Tests/LinuxMain.swift create mode 100644 renovate.json diff --git a/.codecov.yml b/.codecov.yml index 4d717c63..1db9c061 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,5 +1,6 @@ ignore: - "Tests/" + - "Benchmarks/" comment: - layout: header, changes, diff \ No newline at end of file + layout: header, changes, diff diff --git a/.github/workflows/ci-linux.yml b/.github/workflows/ci-linux.yml index 0a608bf3..38fad3a4 100644 --- a/.github/workflows/ci-linux.yml +++ b/.github/workflows/ci-linux.yml @@ -11,29 +11,29 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - swift: ["5.1", "latest"] + swift: ["latest"] container: image: swift:${{ matrix.swift }} steps: - name: Checkout - uses: actions/checkout@master - - name: "Update APT" - shell: bash - run: "apt update" - - name: "Install curl" - shell: bash - run: "apt-get install -y curl" - - name: Swift version - run: swift --version + uses: actions/checkout@v4 + - name: Test - run: swift test -v --skip-update --parallel --enable-test-discovery --enable-code-coverage - - name: Generate coverage report - run: llvm-cov export -format="lcov" .build/debug/*PackageTests.xctest -instr-profile .build/debug/codecov/default.profdata > coverage.lcov - - name: Upload code coverage report - uses: codecov/codecov-action@v1.5.2 + run: swift test -c release --enable-xctest --parallel --xunit-output .build/xUnit-output.xml + + - name: Upload test artifacts + if: failure() + uses: actions/upload-artifact@v4.4.3 with: - token: ${{secrets.CODECOV_TOKEN}} - file: coverage.lcov - fail_ci_if_error: true - - name: Build Release - run: swift build -c release + name: test-artifacts-linux-${{ matrix.swift }}-${{ github.run_id }} + path: | + .build/*.yaml + .build/*.xml + .build/*.json + .build/*.txt + .build/**/*.xctest + .build/**/*.json + .build/**/*.txt + if-no-files-found: warn + include-hidden-files: true + diff --git a/.github/workflows/ci-macos.yml b/.github/workflows/ci-macos.yml index 2db20fca..58641bbe 100644 --- a/.github/workflows/ci-macos.yml +++ b/.github/workflows/ci-macos.yml @@ -5,52 +5,56 @@ on: branches: [ master ] pull_request: branches: [ master ] + workflow_dispatch: + +env: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + CODECOV_XCODE_VERSION: "15.4" # Xcode version used to generate code coverage jobs: macos-test-build-release-xcode: - runs-on: macOS-11 + runs-on: macOS-latest strategy: matrix: - xcode: ["11.7", "12.5.1", "13.0"] + xcode: ["14.3.1", "15.4", "16.0"] + steps: - name: Checkout - uses: actions/checkout@master + uses: actions/checkout@v4 + - name: Select Xcode ${{ matrix.xcode }} run: sudo xcode-select -s /Applications/Xcode_${{ matrix.xcode }}.app + - name: Test - run: swift test -v --skip-update --parallel --enable-test-discovery --enable-code-coverage + run: swift test -c release --parallel --xunit-output .build/xUnit-output.xml --enable-code-coverage env: DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer + - name: Upload test artifacts if: failure() - uses: actions/upload-artifact@v2.2.3 + uses: actions/upload-artifact@v4.4.3 with: name: test-artifacts-${{ matrix.xcode }}-${{ github.run_id }} path: | - .build/**/*.json + .build/*.yaml + .build/*.xml + .build/*.json + .build/*.txt .build/**/*.xctest + .build/**/*.json + .build/**/*.txt + if-no-files-found: warn + include-hidden-files: true + + # Only run coverage steps if the CODECOV_TOKEN is available and the matrix.xcode matches CODECOV_XCODE_VERSION - name: Generate coverage report - run: xcrun llvm-cov export -format="lcov" .build/debug/*PackageTests.xctest/Contents/MacOS/*PackageTests -instr-profile .build/debug/codecov/default.profdata > coverage.lcov + if: env.CODECOV_TOKEN != '' && matrix.xcode == env.CODECOV_XCODE_VERSION + run: xcrun llvm-cov export -format="lcov" .build/**/*PackageTests.xctest/Contents/MacOS/*PackageTests -instr-profile .build/**/codecov/default.profdata > coverage.lcov + - name: Upload code coverage report - uses: codecov/codecov-action@v1.5.2 + if: env.CODECOV_TOKEN != '' && matrix.xcode == env.CODECOV_XCODE_VERSION + uses: codecov/codecov-action@v4.6.0 with: - token: ${{secrets.CODECOV_TOKEN}} + token: ${{ env.CODECOV_TOKEN }} file: coverage.lcov fail_ci_if_error: true - - name: Build Release - run: swift build -c release - env: - DEVELOPER_DIR: /Applications/Xcode_${{ matrix.xcode }}.app/Contents/Developer - - name: Upload build artifacts - if: failure() - uses: actions/upload-artifact@v2.2.3 - with: - name: build-artifacts-${{ matrix.xcode }}-${{ github.run_id }} - path: | - *.lcov - .build/*.yaml - .build/**/*.a - .build/**/*.so - .build/**/*.dylib - .build/**/*.dSYM - .build/**/*.json diff --git a/.github/workflows/ci-wasm.yml b/.github/workflows/ci-wasm.yml index babbaba3..0af195b2 100644 --- a/.github/workflows/ci-wasm.yml +++ b/.github/workflows/ci-wasm.yml @@ -10,8 +10,8 @@ jobs: wasm-build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v4 - name: Build - uses: swiftwasm/swiftwasm-action@main + uses: swiftwasm/swiftwasm-action@v5.9 with: shell-action: swift build --triple wasm32-unknown-wasi diff --git a/.github/workflows/ci-windows.yml b/.github/workflows/ci-windows.yml index 3b75fcd2..ab95135f 100644 --- a/.github/workflows/ci-windows.yml +++ b/.github/workflows/ci-windows.yml @@ -9,30 +9,31 @@ on: jobs: windows-test-build-release: runs-on: windows-latest - env: - SNAPSHOT: "https://swift.org/builds/swift-5.4.1-release/windows10/swift-5.4.1-RELEASE/swift-5.4.1-RELEASE-windows10.exe" steps: - - uses: actions/checkout@master - - uses: seanmiddleditch/gha-setup-vsdevenv@master - - - name: Install Swift - run: | - Install-Binary -Url "${env:SNAPSHOT}" -Name "installer.exe" -ArgumentList ("-q") - - name: Set Environment Variables - run: | - echo "SDKROOT=C:\Library\Developer\Platforms\Windows.platform\Developer\SDKs\Windows.sdk" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - echo "DEVELOPER_DIR=C:\Library\Developer" | Out-File -FilePath $env:GITHUB_ENV -Encoding utf8 -Append - - name: Adjust Paths - run: | - echo "C:\Library\Swift-development\bin;C:\Library\icu-67\usr\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - echo "C:\Library\Developer\Toolchains\unknown-Asserts-development.xctoolchain\usr\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - name: Install Supporting Files - run: | - Copy-Item "$env:SDKROOT\usr\share\ucrt.modulemap" -destination "$env:UniversalCRTSdkDir\Include\$env:UCRTVersion\ucrt\module.modulemap" - Copy-Item "$env:SDKROOT\usr\share\visualc.modulemap" -destination "$env:VCToolsInstallDir\include\module.modulemap" - Copy-Item "$env:SDKROOT\usr\share\visualc.apinotes" -destination "$env:VCToolsInstallDir\include\visualc.apinotes" - Copy-Item "$env:SDKROOT\usr\share\winsdk.modulemap" -destination "$env:UniversalCRTSdkDir\Include\$env:UCRTVersion\um\module.modulemap" - - name: Test - run: swift test -v --skip-update --parallel --enable-test-discovery - - name: Build Release - run: swift build -c release \ No newline at end of file + - name: Setup + uses: compnerd/gha-setup-swift@v0.2.3 + with: + branch: swift-5.10-release + tag: 5.10-RELEASE + + - name: Checkout + uses: actions/checkout@v4 + + - name: Test + run: swift test -c release --parallel --xunit-output .build/xUnit-output.xml + + - name: Upload test artifacts + if: failure() + uses: actions/upload-artifact@v4.4.3 + with: + name: test-artifacts-windows-${{ github.run_id }} + path: | + .build/*.yaml + .build/*.xml + .build/*.json + .build/*.txt + .build/**/*.xctest + .build/**/*.json + .build/**/*.txt + if-no-files-found: warn + include-hidden-files: true diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index ed63bdb3..d6768ce4 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -18,8 +18,8 @@ jobs: steps: - uses: actions/checkout@master - - name: Generate documentation - uses: SwiftDocOrg/swift-doc@master + - name: Generate Swift Doc Documentation + uses: SwiftDocOrg/swift-doc@1.0.0-rc.1 with: inputs: "Sources/FirebladeECS" output: "Documentation" diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 3db58099..00000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,25 +0,0 @@ -image: swift:5.1.3 - -stages: - - test - - build_release - -build_project: - stage: build_release - script: - - swift package reset - - swift build -c release - tags: - - docker - only: - - master - -test_project: - stage: test - variables: - GIT_DEPTH: "50" - script: - - swift package reset - - swift test - tags: - - docker \ No newline at end of file diff --git a/.swift-version b/.swift-version new file mode 100644 index 00000000..3659ea2f --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +5.8 diff --git a/.swiftformat b/.swiftformat new file mode 100644 index 00000000..884cbf3f --- /dev/null +++ b/.swiftformat @@ -0,0 +1,13 @@ +# file options +--exclude Sources/**/*.generated.swift +--exclude Sources/FirebladeECS/Entity+Component.swift # problems with self.get { } +--exclude Tests/**/*.swift + +# format options +--extensionacl on-declarations +--stripunusedargs closure-only +--commas inline +--self remove +--selfrequired get +--disable preferKeyPath +--disable opaqueGenericParameters \ No newline at end of file diff --git a/.swiftlint.yml b/.swiftlint.yml index cfc66117..e32b7d4a 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -9,23 +9,11 @@ identifier_name: line_length: 220 number_separator: minimum_length: 5 +analyzer_rules: + - explicit_self + - unused_declaration + - unused_import opt_in_rules: - #- explicit_acl - #- explicit_enum_raw_value - #- explicit_type_interface - #- extension_access_modifier - #- file_name - #- file_types_order - #- indentation_width - #- missing_docs - #- multiline_arguments_brackets - #- multiline_literal_brackets - #- multiline_parameters_brackets - #- no_grouping_extension - #- required_deinit - #- type_contents_order - #- unowned_variable_capture - - anyobject_protocol - array_init - attributes - closure_body_length @@ -48,7 +36,6 @@ opt_in_rules: - enum_case_associated_values_count - expiring_todo - explicit_init - - explicit_self - explicit_top_level_acl - fallthrough - fatal_error_message @@ -109,8 +96,6 @@ opt_in_rules: - unavailable_function - unneeded_parentheses_in_closure_argument - untyped_error_in_catch - - unused_declaration - - unused_import - vertical_parameter_alignment_on_call - vertical_whitespace_between_cases - vertical_whitespace_closing_braces diff --git a/Benchmarks/Benchmarks/ECSBenchmark/Base.swift b/Benchmarks/Benchmarks/ECSBenchmark/Base.swift new file mode 100644 index 00000000..fe0da9d2 --- /dev/null +++ b/Benchmarks/Benchmarks/ECSBenchmark/Base.swift @@ -0,0 +1,85 @@ +// +// Base.swift +// FirebladeECSTests +// +// Created by Christian Treffs on 09.10.17. +// + +import FirebladeECS + +class EmptyComponent: Component {} + +class Name: Component { + var name: String + init(name: String) { + self.name = name + } +} + +class Position: Component { + var x: Int + var y: Int + init(x: Int, y: Int) { + self.x = x + self.y = y + } +} + +class Velocity: Component { + var a: Float + init(a: Float) { + self.a = a + } +} + +class Party: Component { + var partying: Bool + init(partying: Bool) { + self.partying = partying + } +} + +class Color: Component { + var r: UInt8 = 0 + var g: UInt8 = 0 + var b: UInt8 = 0 +} + +class ExampleSystem { + private let family: Family2 + + init(nexus: Nexus) { + family = nexus.family(requiresAll: Position.self, Velocity.self, excludesAll: EmptyComponent.self) + } + + func update(deltaT _: Double) { + for (position, velocity) in family { + position.x *= 2 + velocity.a *= 2 + } + } +} + +final class SingleGameState: SingleComponent { + var shouldQuit: Bool = false + var playerHealth: Int = 67 +} + +func setUpNexus() -> Nexus { + let numEntities = 10000 + let nexus = Nexus() + + for i in 0 ..< numEntities { + nexus.createEntity().assign(Position(x: 1 + i, y: 2 + i), + Name(name: "myName\(i)"), + Velocity(a: 3.14), + EmptyComponent(), + Color()) + } + + precondition(nexus.numEntities == numEntities) +// precondition(nexus.numFamilies == 1) + precondition(nexus.numComponents == numEntities * 5) + + return nexus +} diff --git a/Benchmarks/Benchmarks/ECSBenchmark/OneDimensionBenchmarks.swift b/Benchmarks/Benchmarks/ECSBenchmark/OneDimensionBenchmarks.swift new file mode 100644 index 00000000..bceee0d6 --- /dev/null +++ b/Benchmarks/Benchmarks/ECSBenchmark/OneDimensionBenchmarks.swift @@ -0,0 +1,198 @@ +// swiftformat:disable preferForLoop +import Benchmark +import FirebladeECS + +// derived from FirebladeECSPerformanceTests/TypedFamilyPerformanceTests.swift in the parent project + +let benchmarks = { + Benchmark("TraitMatching") { benchmark in + let nexus = setUpNexus() + let a = nexus.createEntity() + a.assign(Position(x: 1, y: 2)) + a.assign(Name(name: "myName")) + a.assign(Velocity(a: 3.14)) + a.assign(EmptyComponent()) + + let isMatch = nexus.family(requiresAll: Position.self, Velocity.self, + excludesAll: Party.self) + + for _ in benchmark.scaledIterations { + blackHole( + isMatch.canBecomeMember(a) + ) + } + } + + Benchmark("TypedFamilyEntities") { benchmark in + let nexus = setUpNexus() + let family = nexus.family(requires: Position.self, excludesAll: Party.self) + for _ in benchmark.scaledIterations { + blackHole( + family + .entities + .forEach { (entity: Entity) in + _ = entity + } + ) + } + } + + Benchmark("TypedFamilyOneComponent") { benchmark in + let nexus = setUpNexus() + let family = nexus.family(requires: Position.self, excludesAll: Party.self) + for _ in benchmark.scaledIterations { + blackHole( + family + .forEach { (position: Position) in + _ = position + } + ) + } + } + + Benchmark("TypedFamilyEntityOneComponent") { benchmark in + let nexus = setUpNexus() + let family = nexus.family(requires: Position.self, excludesAll: Party.self) + for _ in benchmark.scaledIterations { + blackHole( + family + .entityAndComponents + .forEach { (entity: Entity, position: Position) in + _ = entity + _ = position + } + ) + } + } + + Benchmark("TypedFamilyTwoComponents") { benchmark in + let nexus = setUpNexus() + let family = nexus.family(requiresAll: Position.self, Velocity.self, excludesAll: Party.self) + for _ in benchmark.scaledIterations { + blackHole( + family + .forEach { (position: Position, velocity: Velocity) in + _ = position + _ = velocity + } + ) + } + } + Benchmark("TypedFamilyEntityTwoComponents") { benchmark in + let nexus = setUpNexus() + let family = nexus.family(requiresAll: Position.self, Velocity.self, excludesAll: Party.self) + for _ in benchmark.scaledIterations { + blackHole( + family + .entityAndComponents + .forEach { (entity: Entity, position: Position, velocity: Velocity) in + _ = entity + _ = position + _ = velocity + } + ) + } + } + + Benchmark("TypedFamilyThreeComponents") { benchmark in + let nexus = setUpNexus() + let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, excludesAll: Party.self) + for _ in benchmark.scaledIterations { + blackHole( + family + .forEach { (position: Position, velocity: Velocity, name: Name) in + _ = position + _ = velocity + _ = name + } + ) + } + } + Benchmark("TypedFamilyEntityThreeComponents") { benchmark in + let nexus = setUpNexus() + let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, excludesAll: Party.self) + for _ in benchmark.scaledIterations { + blackHole( + family + .entityAndComponents + .forEach { (entity: Entity, position: Position, velocity: Velocity, name: Name) in + _ = entity + _ = position + _ = velocity + _ = name + } + ) + } + } + + Benchmark("TypedFamilyFourComponents") { benchmark in + let nexus = setUpNexus() + let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, excludesAll: Party.self) + for _ in benchmark.scaledIterations { + blackHole( + family + .forEach { (position: Position, velocity: Velocity, name: Name, color: Color) in + _ = position + _ = velocity + _ = name + _ = color + } + ) + } + } + + Benchmark("TypedFamilyEntityFourComponents") { benchmark in + let nexus = setUpNexus() + let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, excludesAll: Party.self) + for _ in benchmark.scaledIterations { + blackHole( + family + .entityAndComponents + .forEach { (entity: Entity, position: Position, velocity: Velocity, name: Name, color: Color) in + _ = entity + _ = position + _ = velocity + _ = name + _ = color + } + ) + } + } + + Benchmark("TypedFamilyFiveComponents") { benchmark in + let nexus = setUpNexus() + let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, EmptyComponent.self, excludesAll: Party.self) + + for _ in benchmark.scaledIterations { + blackHole( + family + .forEach { (position: Position, velocity: Velocity, name: Name, color: Color, empty: EmptyComponent) in + _ = position + _ = velocity + _ = name + _ = color + _ = empty + } + ) + } + } + + Benchmark("TypedFamilyEntityFiveComponents") { benchmark in + let nexus = setUpNexus() + let family = nexus.family(requiresAll: Position.self, Velocity.self, Name.self, Color.self, EmptyComponent.self, excludesAll: Party.self) + + for _ in benchmark.scaledIterations { + blackHole(family + .entityAndComponents + .forEach { (entity: Entity, position: Position, velocity: Velocity, name: Name, color: Color, empty: EmptyComponent) in + _ = entity + _ = position + _ = velocity + _ = name + _ = color + _ = empty + } + ) + } + } +} diff --git a/Benchmarks/Package.swift b/Benchmarks/Package.swift new file mode 100644 index 00000000..62656d19 --- /dev/null +++ b/Benchmarks/Package.swift @@ -0,0 +1,28 @@ +// swift-tools-version: 5.8 + +import PackageDescription + +let package = Package( + name: "ECSBenchmarks", + platforms: [ + .iOS(.v16), + .macOS(.v13) + ], + dependencies: [ + .package(path: "../"), + .package(url: "https://github.com/ordo-one/package-benchmark", .upToNextMajor(from: "1.4.0")) + ], + targets: [ + .executableTarget( + name: "ECSBenchmark", + dependencies: [ + .product(name: "FirebladeECS", package: "ecs"), + .product(name: "Benchmark", package: "package-benchmark") + ], + path: "Benchmarks/ECSBenchmark", + plugins: [ + .plugin(name: "BenchmarkPlugin", package: "package-benchmark") + ] + ) + ] +) diff --git a/Benchmarks/README.md b/Benchmarks/README.md new file mode 100644 index 00000000..0d525f65 --- /dev/null +++ b/Benchmarks/README.md @@ -0,0 +1,22 @@ +# Benchmarks for FirebladeECS + +Originally seeded by replicating performance tests into a new form leveraging [package-benchmark](https://swiftpackageindex.com/ordo-one/package-benchmark/) [Documentation](https://swiftpackageindex.com/ordo-one/package-benchmark/main/documentation/benchmark). + +To run all the available benchmarks: + + swift package benchmark --format markdown + +For more help on the package-benchmark SwiftPM plugin: + + swift package benchmark help + +Creating a local baseline: + + swift package --allow-writing-to-package-directory benchmark baseline update dev + swift package benchmark baseline list + +Comparing to a the baseline 'alpha' + + swift package benchmark baseline compare dev + +For more details on creating and comparing baselines, read [Creating and Comparing Benchmark Baselines](https://swiftpackageindex.com/ordo-one/package-benchmark/main/documentation/benchmark/creatingandcomparingbaselines). diff --git a/Makefile b/Makefile index ecb71093..7518a328 100644 --- a/Makefile +++ b/Makefile @@ -1,79 +1,61 @@ -# Version 1.0.0 -UNAME_S := $(shell uname -s) - -# Lint -lint: - swiftlint autocorrect --format - swiftlint lint --quiet - -lintErrorOnly: - @swiftlint autocorrect --format --quiet - @swiftlint lint --quiet | grep error - -# Git -precommit: generateCode generateTestsCode lint genLinuxTests - -submodule: - git submodule init - git submodule update --recursive - -# Tests -genLinuxTests: - swift test --generate-linuxmain - swiftlint autocorrect --format --path Tests/ - -test: genLinuxTests - swift test - -# Package -latest: - swift package update - -resolve: - swift package resolve - -# Xcode -genXcode: - swift package generate-xcodeproj --enable-code-coverage --skip-extra-files - -genXcodeOpen: genXcode - open *.xcodeproj - -# Clean -clean: - swift package reset - -rm -rdf .swiftpm/xcode - -rm -rdf .build/ - -rm Package.resolved - -rm .DS_Store - -cleanArtifacts: - swift package clean +SWIFT_PACKAGE_VERSION := $(shell swift package tools-version) + +# Lint fix and format code. +.PHONY: lint-fix +swiftlint: + mint run swiftlint lint --fix --config .swiftlint.yml --format --quiet +swiftformat: + mint run swiftformat . --swiftversion ${SWIFT_PACKAGE_VERSION} +lint-fix: swiftlint swiftformat + +# Generate code +.PHONY: generate-code +generate-code: + mint run sourcery --quiet --config ./.sourcery.yml + mint run sourcery --quiet --config ./.sourceryTests.yml + +# Run pre-push tasks +.PHONY: pre-push +pre-push: generate-code lint-fix + +.PHONY: precommit +precommit: pre-push + +.PHONY: setup-brew +setup-brew: + @which -s brew || /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" + @brew update + +.PHONY: install-dependencies-macOS +install-dependencies-macOS: setup-brew + brew install mint + mint bootstrap + +.PHONY: setupEnvironment +setupEnvironment: install-dependencies-macOS + +# Build debug version +.PHONY: build-debug +build-debug: + swift build -c debug + +# Build release version +.PHONY: build-release +build-release: + swift build -c release --skip-update # Test links in README # requires +.PHONY: testReadme testReadme: markdown-link-check -p -v ./README.md -generateCode: - sourcery --config ./.sourcery.yml --verbose -generateTestsCode: - sourcery --config ./.sourceryTests.yml --verbose - -brewInstallDeps: brewUpdate - brew install swiftenv - brew install swiftlint - brew install sourcery - -brewSetup: - which -s brew || /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" - -brewUpdate: brewSetup - brew update - -setupEnvironment: brewInstallDeps - open Package.swift +# Delete package build artifacts. +.PHONY: clean +clean: clean-sourcery + swift package clean -# lines of code -loc: clean - find . -name "*.swift" -print0 | xargs -0 wc -l +# Clean sourcery cache +.PHONY: clean-sourcery +clean-sourcery: + rm -rdf ${HOME}/Library/Caches/Sourcery diff --git a/Mintfile b/Mintfile new file mode 100644 index 00000000..cf6a9886 --- /dev/null +++ b/Mintfile @@ -0,0 +1,3 @@ +realm/SwiftLint@0.57.0 +nicklockwood/SwiftFormat@0.54.6 +krzysztofzablocki/Sourcery@2.2.5 diff --git a/Package.swift b/Package.swift index 36f03a20..424738dd 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.1 +// swift-tools-version:5.8 import PackageDescription let package = Package( @@ -8,9 +8,11 @@ let package = Package( targets: ["FirebladeECS"]) ], targets: [ - .target(name: "FirebladeECS"), + .target(name: "FirebladeECS", + exclude: ["Stencils/Family.stencil"]), .testTarget(name: "FirebladeECSTests", - dependencies: ["FirebladeECS"]), + dependencies: ["FirebladeECS"], + exclude: ["Stencils/FamilyTests.stencil"]), .testTarget(name: "FirebladeECSPerformanceTests", dependencies: ["FirebladeECS"]) ], diff --git a/README.md b/README.md index 081d175d..d5549422 100644 --- a/README.md +++ b/README.md @@ -25,19 +25,19 @@ These instructions will get you a copy of the project up and running on your loc ### 💻 Installing -Fireblade ECS is available for all platforms that support [Swift 5.1](https://swift.org/) and higher and the [Swift Package Manager (SPM)](https://github.com/apple/swift-package-manager). +Fireblade ECS is available for all platforms that support [Swift 5.8](https://swift.org/) and higher and the [Swift Package Manager (SPM)](https://github.com/apple/swift-package-manager). Extend the following lines in your `Package.swift` file or use it to create a new project. ```swift -// swift-tools-version:5.1 +// swift-tools-version:5.8 import PackageDescription let package = Package( name: "YourPackageName", dependencies: [ - .package(url: "https://github.com/fireblade-engine/ecs.git", from: "0.17.4") + .package(url: "https://github.com/fireblade-engine/ecs.git", from: "0.17.5") ], targets: [ .target( diff --git a/Sources/FirebladeECS/CodingStrategy.swift b/Sources/FirebladeECS/CodingStrategy.swift index 5b898486..17906370 100644 --- a/Sources/FirebladeECS/CodingStrategy.swift +++ b/Sources/FirebladeECS/CodingStrategy.swift @@ -13,6 +13,6 @@ public struct DynamicCodingKey: CodingKey { public var intValue: Int? public var stringValue: String - public init?(intValue: Int) { self.intValue = intValue; self.stringValue = "\(intValue)" } + public init?(intValue: Int) { self.intValue = intValue; stringValue = "\(intValue)" } public init?(stringValue: String) { self.stringValue = stringValue } } diff --git a/Sources/FirebladeECS/ComponentIdentifier.swift b/Sources/FirebladeECS/ComponentIdentifier.swift index 72fc9e55..79e62476 100644 --- a/Sources/FirebladeECS/ComponentIdentifier.swift +++ b/Sources/FirebladeECS/ComponentIdentifier.swift @@ -13,15 +13,15 @@ public struct ComponentIdentifier { extension ComponentIdentifier { @usableFromInline - init(_ componentType: C.Type) where C: Component { - self.id = Self.makeRuntimeHash(componentType) + init(_ componentType: (some Component).Type) { + id = Self.makeRuntimeHash(componentType) } /// object identifier hash (only stable during runtime) - arbitrary hash is ok. - internal static func makeRuntimeHash(_ componentType: C.Type) -> Identifier where C: Component { + static func makeRuntimeHash(_ componentType: (some Component).Type) -> Identifier { ObjectIdentifier(componentType).hashValue } } -extension ComponentIdentifier: Equatable { } -extension ComponentIdentifier: Hashable { } +extension ComponentIdentifier: Equatable {} +extension ComponentIdentifier: Hashable {} diff --git a/Sources/FirebladeECS/Entity.swift b/Sources/FirebladeECS/Entity.swift index 33e3ff20..6ab62cfe 100644 --- a/Sources/FirebladeECS/Entity.swift +++ b/Sources/FirebladeECS/Entity.swift @@ -17,9 +17,9 @@ public struct Entity { /// The unique entity identifier. public private(set) var identifier: EntityIdentifier - internal init(nexus: Nexus, id: EntityIdentifier) { + init(nexus: Nexus, id: EntityIdentifier) { self.nexus = nexus - self.identifier = id + identifier = id } /// Returns the number of components for this entity. @@ -38,13 +38,13 @@ public struct Entity { } @discardableResult - public func createEntity(with components: C) -> Entity where C: Collection, C.Element == Component { + public func createEntity(with components: some Collection) -> Entity { nexus.createEntity(with: components) } /// Checks if a component with given type is assigned to this entity. /// - Parameter type: the component type. - public func has(_ type: C.Type) -> Bool where C: Component { + public func has(_ type: (some Component).Type) -> Bool { has(type.identifier) } @@ -78,13 +78,13 @@ public struct Entity { /// Add a typed component to this entity. /// - Parameter component: the typed component. @discardableResult - public func assign(_ component: C) -> Entity where C: Component { + public func assign(_ component: some Component) -> Entity { assign(component) return self } @discardableResult - public func assign(_ components: C) -> Entity where C: Collection, C.Element == Component { + public func assign(_ components: some Collection) -> Entity { nexus.assign(components: components, to: self) return self } @@ -92,14 +92,14 @@ public struct Entity { /// Remove a component from this entity. /// - Parameter component: the component. @discardableResult - public func remove(_ component: C) -> Entity where C: Component { + public func remove(_ component: some Component) -> Entity { remove(component.identifier) } /// Remove a component by type from this entity. /// - Parameter compType: the component type. @discardableResult - public func remove(_ compType: C.Type) -> Entity where C: Component { + public func remove(_ compType: (some Component).Type) -> Entity { remove(compType.identifier) } @@ -130,7 +130,7 @@ public struct Entity { extension Entity { public struct ComponentsIterator: IteratorProtocol { - private var iterator: IndexingIterator<([Component])>? + private var iterator: IndexingIterator<[Component]>? @usableFromInline init(nexus: Nexus, entityIdentifier: EntityIdentifier) { @@ -144,8 +144,9 @@ extension Entity { } } } -extension Entity.ComponentsIterator: LazySequenceProtocol { } -extension Entity.ComponentsIterator: Sequence { } + +extension Entity.ComponentsIterator: LazySequenceProtocol {} +extension Entity.ComponentsIterator: Sequence {} extension Entity: Equatable { public static func == (lhs: Entity, rhs: Entity) -> Bool { diff --git a/Sources/FirebladeECS/EntityIdentifier.swift b/Sources/FirebladeECS/EntityIdentifier.swift index 6c2e98ee..f8676b60 100644 --- a/Sources/FirebladeECS/EntityIdentifier.swift +++ b/Sources/FirebladeECS/EntityIdentifier.swift @@ -23,8 +23,8 @@ public struct EntityIdentifier { } } -extension EntityIdentifier: Equatable { } -extension EntityIdentifier: Hashable { } +extension EntityIdentifier: Equatable {} +extension EntityIdentifier: Hashable {} extension EntityIdentifier: RawRepresentable { /// The entity identifier represented as a raw value. @@ -33,7 +33,7 @@ extension EntityIdentifier: RawRepresentable { @inlinable public init(rawValue: Identifier) { - self.id = rawValue + id = rawValue } } diff --git a/Sources/FirebladeECS/EntityIdentifierGenerator.swift b/Sources/FirebladeECS/EntityIdentifierGenerator.swift index 1c9a0356..1d6434bc 100644 --- a/Sources/FirebladeECS/EntityIdentifierGenerator.swift +++ b/Sources/FirebladeECS/EntityIdentifierGenerator.swift @@ -49,10 +49,10 @@ public struct LinearIncrementingEntityIdGenerator: EntityIdentifierGenerator { @usableFromInline init(startProviding initialEntityIds: EntityIds) where EntityIds: BidirectionalCollection, EntityIds.Element == EntityIdentifier { - let initialInUse: [EntityIdentifier.Identifier] = initialEntityIds.map { $0.id } + let initialInUse: [EntityIdentifier.Identifier] = initialEntityIds.map(\.id) let maxInUseValue = initialInUse.max() ?? 0 let inUseSet = Set(initialInUse) // a set of all eIds in use - let allSet = Set(0...maxInUseValue) // all eIds from 0 to including maxInUseValue + let allSet = Set(0 ... maxInUseValue) // all eIds from 0 to including maxInUseValue let freeSet = allSet.subtracting(inUseSet) // all "holes" / unused / free eIds let initialFree = Array(freeSet).sorted().reversed() // order them to provide them linear increasing after all initially used are provided. stack = initialFree + initialInUse @@ -83,12 +83,12 @@ public struct LinearIncrementingEntityIdGenerator: EntityIdentifierGenerator { @inlinable public init(startProviding initialEntityIds: EntityIds) where EntityIds: BidirectionalCollection, EntityIds.Element == EntityIdentifier { - self.storage = Storage(startProviding: initialEntityIds) + storage = Storage(startProviding: initialEntityIds) } @inlinable public init() { - self.storage = Storage() + storage = Storage() } @inline(__always) diff --git a/Sources/FirebladeECS/FSM.swift b/Sources/FirebladeECS/FSM.swift index 8d33c248..5ae3052b 100644 --- a/Sources/FirebladeECS/FSM.swift +++ b/Sources/FirebladeECS/FSM.swift @@ -97,9 +97,7 @@ public protocol DefaultInitializable { ///// This component provider always returns the same instance of the component. The instance ///// is created when first required and is of the type passed in to the initializer. //public final class ComponentSingletonProvider { -// private lazy var instance: Component = { -// componentType.init() -// }() +// private lazy var instance: Component = componentType.init() // // private var componentType: ComponentInitializable.Type // @@ -171,7 +169,7 @@ public protocol DefaultInitializable { ///// Represents a state for an EntityStateMachine. The state contains any number of ComponentProviders which ///// are used to add components to the entity when this state is entered. //public class EntityState { -// internal var providers = [ComponentIdentifier: ComponentProvider]() +// var providers = [ComponentIdentifier: ComponentProvider]() // // public init() {} // @@ -253,7 +251,7 @@ public protocol DefaultInitializable { // /// - Returns: This EntityState, so more modifications can be applied. // @inline(__always) // @discardableResult -// public func addProvider(type: C.Type, provider: ComponentProvider) -> Self { +// public func addProvider(type: (some ComponentInitializable).Type, provider: ComponentProvider) -> Self { // addMapping(for: type).withProvider(provider) // return self // } @@ -272,7 +270,7 @@ public protocol DefaultInitializable { // /// by more specific mappings if other methods are called. // /// - Parameter creatingState: The EntityState that the mapping will belong to // /// - Parameter type: The component type for the mapping -// internal init(creatingState: EntityState, type: ComponentInitializable.Type) { +// init(creatingState: EntityState, type: ComponentInitializable.Type) { // self.creatingState = creatingState // componentType = type // provider = ComponentTypeProvider(type: type) @@ -318,7 +316,7 @@ public protocol DefaultInitializable { // /// - Parameter closure: The Closure instance to return the component instance // /// - Returns: This ComponentMapping, so more modifications can be applied // @discardableResult -// public func withMethod(_ closure: DynamicComponentProvider.Closure) -> Self { +// public func withMethod(_ closure: DynamicComponentProvider.Closure) -> Self { // setProvider(DynamicComponentProvider(closure: closure)) // return self // } @@ -403,7 +401,7 @@ public protocol DefaultInitializable { // // var toAdd: [ComponentIdentifier: ComponentProvider] // -// if let currentState = currentState { +// if let currentState { // toAdd = .init() // for (identifier, provider) in newState.providers { // toAdd[identifier] = provider @@ -411,7 +409,8 @@ public protocol DefaultInitializable { // // for (identifier, _) in currentState.providers { // if let other = toAdd[identifier], let current = currentState.providers[identifier], -// current.identifier == other.identifier { +// current.identifier == other.identifier +// { // toAdd[identifier] = nil // } else { // entity.remove(identifier) diff --git a/Sources/FirebladeECS/Family+Coding.swift b/Sources/FirebladeECS/Family+Coding.swift index 8de86992..1048d073 100644 --- a/Sources/FirebladeECS/Family+Coding.swift +++ b/Sources/FirebladeECS/Family+Coding.swift @@ -14,6 +14,7 @@ extension CodingUserInfoKey { } // MARK: - encoding + extension FamilyMemberContainer: Encodable where R: FamilyEncoding { func encode(to encoder: Encoder) throws { let strategy = encoder.userInfo[.nexusCodingStrategy] as? CodingStrategy ?? DefaultCodingStrategy() @@ -50,11 +51,12 @@ extension Family where R: FamilyEncoding { } // MARK: - decoding + extension FamilyMemberContainer: Decodable where R: FamilyDecoding { init(from decoder: Decoder) throws { var familyContainer = try decoder.unkeyedContainer() let strategy = decoder.userInfo[.nexusCodingStrategy] as? CodingStrategy ?? DefaultCodingStrategy() - self.components = try R.decode(componentsIn: &familyContainer, using: strategy) + components = try R.decode(componentsIn: &familyContainer, using: strategy) } } diff --git a/Sources/FirebladeECS/Family.swift b/Sources/FirebladeECS/Family.swift index ba5749e5..9b2f13d8 100644 --- a/Sources/FirebladeECS/Family.swift +++ b/Sources/FirebladeECS/Family.swift @@ -53,7 +53,7 @@ public struct Family where R: FamilyRequirementsManaging { /// - Returns: The newly created member entity. @discardableResult public func createMember(@FamilyMemberBuilder using builder: () -> R.Components) -> Entity { - self.createMember(with: builder()) + createMember(with: builder()) } } @@ -70,16 +70,17 @@ extension Family: Sequence { } } -extension Family: LazySequenceProtocol { } +extension Family: LazySequenceProtocol {} // MARK: - components iterator + extension Family { public struct ComponentsIterator: IteratorProtocol { @usableFromInline var memberIdsIterator: UnorderedSparseSet.ElementIterator @usableFromInline unowned let nexus: Nexus public init(family: Family) { - self.nexus = family.nexus + nexus = family.nexus memberIdsIterator = family.memberIds.makeIterator() } @@ -93,10 +94,11 @@ extension Family { } } -extension Family.ComponentsIterator: LazySequenceProtocol { } -extension Family.ComponentsIterator: Sequence { } +extension Family.ComponentsIterator: LazySequenceProtocol {} +extension Family.ComponentsIterator: Sequence {} // MARK: - entity iterator + extension Family { @inlinable public var entities: EntityIterator { EntityIterator(family: self) @@ -107,7 +109,7 @@ extension Family { @usableFromInline unowned let nexus: Nexus public init(family: Family) { - self.nexus = family.nexus + nexus = family.nexus memberIdsIterator = family.memberIds.makeIterator() } @@ -120,10 +122,11 @@ extension Family { } } -extension Family.EntityIterator: LazySequenceProtocol { } -extension Family.EntityIterator: Sequence { } +extension Family.EntityIterator: LazySequenceProtocol {} +extension Family.EntityIterator: Sequence {} // MARK: - entity component iterator + extension Family { @inlinable public var entityAndComponents: EntityComponentIterator { EntityComponentIterator(family: self) @@ -134,7 +137,7 @@ extension Family { @usableFromInline unowned let nexus: Nexus public init(family: Family) { - self.nexus = family.nexus + nexus = family.nexus memberIdsIterator = family.memberIds.makeIterator() } @@ -147,10 +150,11 @@ extension Family { } } -extension Family.EntityComponentIterator: LazySequenceProtocol { } -extension Family.EntityComponentIterator: Sequence { } +extension Family.EntityComponentIterator: LazySequenceProtocol {} +extension Family.EntityComponentIterator: Sequence {} // MARK: - member creation + extension Family { /// Create a new entity with components required by this family. /// diff --git a/Sources/FirebladeECS/FamilyMemberBuilder.swift b/Sources/FirebladeECS/FamilyMemberBuilder.swift index 044cc54a..1d281fdf 100644 --- a/Sources/FirebladeECS/FamilyMemberBuilder.swift +++ b/Sources/FirebladeECS/FamilyMemberBuilder.swift @@ -6,9 +6,9 @@ // #if swift(<5.4) -@_functionBuilder -public enum FamilyMemberBuilder where R: FamilyRequirementsManaging { } + @_functionBuilder + public enum FamilyMemberBuilder where R: FamilyRequirementsManaging {} #else -@resultBuilder -public enum FamilyMemberBuilder where R: FamilyRequirementsManaging { } + @resultBuilder + public enum FamilyMemberBuilder where R: FamilyRequirementsManaging {} #endif diff --git a/Sources/FirebladeECS/FamilyTraitSet.swift b/Sources/FirebladeECS/FamilyTraitSet.swift index 3da947ec..8da4a2eb 100644 --- a/Sources/FirebladeECS/FamilyTraitSet.swift +++ b/Sources/FirebladeECS/FamilyTraitSet.swift @@ -19,7 +19,7 @@ public struct FamilyTraitSet { self.requiresAll = requiresAll self.excludesAll = excludesAll - self.setHash = FirebladeECS.hash(combine: [requiresAll, excludesAll]) + setHash = FirebladeECS.hash(combine: [requiresAll, excludesAll]) } @inlinable diff --git a/Sources/FirebladeECS/Foundation+Extensions.swift b/Sources/FirebladeECS/Foundation+Extensions.swift index c7ff0cf6..4ae06f1d 100644 --- a/Sources/FirebladeECS/Foundation+Extensions.swift +++ b/Sources/FirebladeECS/Foundation+Extensions.swift @@ -6,8 +6,8 @@ // #if canImport(Foundation) -import Foundation + import Foundation -extension JSONEncoder: TopLevelEncoder { } -extension JSONDecoder: TopLevelDecoder { } + extension JSONEncoder: TopLevelEncoder {} + extension JSONDecoder: TopLevelDecoder {} #endif diff --git a/Sources/FirebladeECS/Generated/Family.generated.swift b/Sources/FirebladeECS/Generated/Family.generated.swift index 5e9147d3..f67e0965 100644 --- a/Sources/FirebladeECS/Generated/Family.generated.swift +++ b/Sources/FirebladeECS/Generated/Family.generated.swift @@ -1,4 +1,4 @@ -// Generated using Sourcery 1.6.1 — https://github.com/krzysztofzablocki/Sourcery +// Generated using Sourcery 2.2.5 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // swiftlint:disable file_length // swiftlint:disable function_parameter_count @@ -27,7 +27,7 @@ public struct Requires1: FamilyRequirementsManaging where Comp1: Componen } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) return (entity, comp1) } @@ -39,9 +39,9 @@ public struct Requires1: FamilyRequirementsManaging where Comp1: Componen extension Requires1: RequiringComponents1 { } -extension FamilyMemberBuilder where R: RequiringComponents1 { +extension FamilyMemberBuilder where R: RequiringComponents1 { public static func buildBlock(_ comp1: R.Comp1) -> (R.Components) { - return (comp1) + (comp1) } } @@ -121,7 +121,7 @@ public struct Requires2: FamilyRequirementsManaging where Comp1: C } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) return (entity, comp1, comp2) @@ -134,9 +134,9 @@ public struct Requires2: FamilyRequirementsManaging where Comp1: C extension Requires2: RequiringComponents2 { } -extension FamilyMemberBuilder where R: RequiringComponents2 { +extension FamilyMemberBuilder where R: RequiringComponents2 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2) -> (R.Components) { - return (comp1, comp2) + (comp1, comp2) } } @@ -221,7 +221,7 @@ public struct Requires3: FamilyRequirementsManaging where C } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -235,9 +235,9 @@ public struct Requires3: FamilyRequirementsManaging where C extension Requires3: RequiringComponents3 { } -extension FamilyMemberBuilder where R: RequiringComponents3 { +extension FamilyMemberBuilder where R: RequiringComponents3 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3) -> (R.Components) { - return (comp1, comp2, comp3) + (comp1, comp2, comp3) } } @@ -327,7 +327,7 @@ public struct Requires4: FamilyRequirementsManaging } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -342,9 +342,9 @@ public struct Requires4: FamilyRequirementsManaging extension Requires4: RequiringComponents4 { } -extension FamilyMemberBuilder where R: RequiringComponents4 { +extension FamilyMemberBuilder where R: RequiringComponents4 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4) -> (R.Components) { - return (comp1, comp2, comp3, comp4) + (comp1, comp2, comp3, comp4) } } @@ -439,7 +439,7 @@ public struct Requires5: FamilyRequirementsMa } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -455,9 +455,9 @@ public struct Requires5: FamilyRequirementsMa extension Requires5: RequiringComponents5 { } -extension FamilyMemberBuilder where R: RequiringComponents5 { +extension FamilyMemberBuilder where R: RequiringComponents5 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5) -> (R.Components) { - return (comp1, comp2, comp3, comp4, comp5) + (comp1, comp2, comp3, comp4, comp5) } } @@ -557,7 +557,7 @@ public struct Requires6: FamilyRequire } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -574,9 +574,9 @@ public struct Requires6: FamilyRequire extension Requires6: RequiringComponents6 { } -extension FamilyMemberBuilder where R: RequiringComponents6 { +extension FamilyMemberBuilder where R: RequiringComponents6 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6) -> (R.Components) { - return (comp1, comp2, comp3, comp4, comp5, comp6) + (comp1, comp2, comp3, comp4, comp5, comp6) } } @@ -681,7 +681,7 @@ public struct Requires7: Family } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -699,9 +699,9 @@ public struct Requires7: Family extension Requires7: RequiringComponents7 { } -extension FamilyMemberBuilder where R: RequiringComponents7 { +extension FamilyMemberBuilder where R: RequiringComponents7 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6, _ comp7: R.Comp7) -> (R.Components) { - return (comp1, comp2, comp3, comp4, comp5, comp6, comp7) + (comp1, comp2, comp3, comp4, comp5, comp6, comp7) } } @@ -811,7 +811,7 @@ public struct Requires8: } public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -830,9 +830,9 @@ public struct Requires8: extension Requires8: RequiringComponents8 { } -extension FamilyMemberBuilder where R: RequiringComponents8 { +extension FamilyMemberBuilder where R: RequiringComponents8 { public static func buildBlock(_ comp1: R.Comp1, _ comp2: R.Comp2, _ comp3: R.Comp3, _ comp4: R.Comp4, _ comp5: R.Comp5, _ comp6: R.Comp6, _ comp7: R.Comp7, _ comp8: R.Comp8) -> (R.Components) { - return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8) + (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8) } } @@ -947,7 +947,7 @@ public struct Requires9 (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -967,9 +967,9 @@ public struct Requires9 (R.Components) { - return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9) + (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9) } } @@ -1089,7 +1089,7 @@ public struct Requires10 (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -1110,9 +1110,9 @@ public struct Requires10 (R.Components) { - return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10) + (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10) } } @@ -1237,7 +1237,7 @@ public struct Requires11 (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -1259,9 +1259,9 @@ public struct Requires11 (R.Components) { - return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11) + (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11) } } @@ -1391,7 +1391,7 @@ public struct Requires12 (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -1414,9 +1414,9 @@ public struct Requires12 (R.Components) { - return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12) + (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12) } } @@ -1551,7 +1551,7 @@ public struct Requires13 (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -1575,9 +1575,9 @@ public struct Requires13 (R.Components) { - return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13) + (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13) } } @@ -1717,7 +1717,7 @@ public struct Requires14 (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -1742,9 +1742,9 @@ public struct Requires14 (R.Components) { - return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14) + (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14) } } @@ -1889,7 +1889,7 @@ public struct Requires15 (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -1915,9 +1915,9 @@ public struct Requires15 (R.Components) { - return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15) + (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15) } } @@ -2067,7 +2067,7 @@ public struct Requires16 (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8, Comp9, Comp10, Comp11, Comp12, Comp13, Comp14, Comp15, Comp16) { - let entity: Entity = Entity(nexus: nexus, id: entityId) + let entity = Entity(nexus: nexus, id: entityId) let comp1: Comp1 = nexus.get(unsafe: entityId) let comp2: Comp2 = nexus.get(unsafe: entityId) let comp3: Comp3 = nexus.get(unsafe: entityId) @@ -2094,9 +2094,9 @@ public struct Requires16 (R.Components) { - return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15, comp16) + (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8, comp9, comp10, comp11, comp12, comp13, comp14, comp15, comp16) } } diff --git a/Sources/FirebladeECS/Hashing.swift b/Sources/FirebladeECS/Hashing.swift index d319029f..033b946e 100644 --- a/Sources/FirebladeECS/Hashing.swift +++ b/Sources/FirebladeECS/Hashing.swift @@ -6,11 +6,11 @@ // #if arch(x86_64) || arch(arm64) || arch(powerpc64) || arch(powerpc64le) || arch(s390x) // 64 bit -private let kFibA: UInt = 0x9e3779b97f4a7c15 // = 11400714819323198485 aka Fibonacci Hash a value for 2^64; calculate by: 2^64 / (golden ratio) + private let kFibA: UInt = 0x9E37_79B9_7F4A_7C15 // = 11400714819323198485 aka Fibonacci Hash a value for 2^64; calculate by: 2^64 / (golden ratio) #elseif arch(i386) || arch(arm) || os(watchOS) || arch(wasm32) // 32 bit -private let kFibA: UInt = 0x9e3779b9 // = 2654435769 aka Fibonacci Hash a value for 2^32; calculate by: 2^32 / (golden ratio) + private let kFibA: UInt = 0x9E37_79B9 // = 2654435769 aka Fibonacci Hash a value for 2^32; calculate by: 2^32 / (golden ratio) #else -#error("unsupported architecture") + #error("unsupported architecture") #endif /// entity id ^ component identifier hash @@ -20,6 +20,7 @@ public typealias EntityComponentHash = Int public typealias ComponentTypeHash = Int // MARK: - hash combine + /// Calculates the combined hash of two values. This implementation is based on boost::hash_combine. /// Will always produce the same result for the same combination of seed and value during the single run of a program. /// @@ -55,27 +56,29 @@ public func hash(combine hashValues: H) -> Int where H.Element: Has } // MARK: - entity component hash + extension EntityComponentHash { - internal static func compose(entityId: EntityIdentifier, componentTypeHash: ComponentTypeHash) -> EntityComponentHash { + static func compose(entityId: EntityIdentifier, componentTypeHash: ComponentTypeHash) -> EntityComponentHash { let entityIdSwapped = UInt(entityId.id).byteSwapped // needs to be 64 bit let componentTypeHashUInt = UInt(bitPattern: componentTypeHash) let hashUInt: UInt = componentTypeHashUInt ^ entityIdSwapped return Int(bitPattern: hashUInt) } - internal static func decompose(_ hash: EntityComponentHash, with entityId: EntityIdentifier) -> ComponentTypeHash { + static func decompose(_ hash: EntityComponentHash, with entityId: EntityIdentifier) -> ComponentTypeHash { let entityIdSwapped = UInt(entityId.id).byteSwapped let entityIdSwappedInt = Int(bitPattern: entityIdSwapped) return hash ^ entityIdSwappedInt } - internal static func decompose(_ hash: EntityComponentHash, with componentTypeHash: ComponentTypeHash) -> EntityIdentifier { + static func decompose(_ hash: EntityComponentHash, with componentTypeHash: ComponentTypeHash) -> EntityIdentifier { let entityId: Int = (hash ^ componentTypeHash).byteSwapped return EntityIdentifier(UInt32(truncatingIfNeeded: entityId)) } } // MARK: - string hashing + /// public enum StringHashing { /// *Waren Singer djb2* @@ -85,7 +88,7 @@ public enum StringHashing { var hash: UInt64 = 5381 var iter = utf8String.unicodeScalars.makeIterator() while let char = iter.next() { - hash = 127 * (hash & 0xFFFFFFFFFFFFFF) &+ UInt64(char.value) + hash = 127 * (hash & 0xFF_FFFF_FFFF_FFFF) &+ UInt64(char.value) } return hash } diff --git a/Sources/FirebladeECS/ManagedContiguousArray.swift b/Sources/FirebladeECS/ManagedContiguousArray.swift index 5d627b1f..9f00950e 100644 --- a/Sources/FirebladeECS/ManagedContiguousArray.swift +++ b/Sources/FirebladeECS/ManagedContiguousArray.swift @@ -92,6 +92,7 @@ public struct ManagedContiguousArray { } // MARK: - Equatable + extension ManagedContiguousArray: Equatable where Element: Equatable { public static func == (lhs: ManagedContiguousArray, rhs: ManagedContiguousArray) -> Bool { lhs.store == rhs.store @@ -99,4 +100,5 @@ extension ManagedContiguousArray: Equatable where Element: Equatable { } // MARK: - Codable -extension ManagedContiguousArray: Codable where Element: Codable { } + +extension ManagedContiguousArray: Codable where Element: Codable {} diff --git a/Sources/FirebladeECS/Nexus+Component.swift b/Sources/FirebladeECS/Nexus+Component.swift index 6bd988b0..8ddb0a10 100644 --- a/Sources/FirebladeECS/Nexus+Component.swift +++ b/Sources/FirebladeECS/Nexus+Component.swift @@ -28,12 +28,12 @@ extension Nexus { } @discardableResult - public final func assign(component: C, to entity: Entity) -> Bool where C: Component { + public final func assign(component: some Component, to entity: Entity) -> Bool { assign(component: component, to: entity) } @discardableResult - public final func assign(components: C, to entity: Entity) -> Bool where C: Collection, C.Element == Component { + public final func assign(components: some Collection, to entity: Entity) -> Bool { assign(components: components, to: entity.identifier) } @@ -93,7 +93,7 @@ extension Nexus { return false } var iter = allComponents.makeIterator() - var removedAll: Bool = true + var removedAll = true while let component = iter.next() { removedAll = removedAll && remove(component: component, from: entityId) } diff --git a/Sources/FirebladeECS/Nexus+ComponentsBuilder.swift b/Sources/FirebladeECS/Nexus+ComponentsBuilder.swift index ce4b293a..d1cd65bd 100644 --- a/Sources/FirebladeECS/Nexus+ComponentsBuilder.swift +++ b/Sources/FirebladeECS/Nexus+ComponentsBuilder.swift @@ -6,11 +6,11 @@ // #if swift(<5.4) -@_functionBuilder -public enum ComponentsBuilder { } + @_functionBuilder + public enum ComponentsBuilder {} #else -@resultBuilder -public enum ComponentsBuilder { } + @resultBuilder + public enum ComponentsBuilder {} #endif extension ComponentsBuilder { @@ -39,7 +39,7 @@ extension Nexus { /// - Returns: The newly created entity with the provided component assigned. @discardableResult public func createEntity(@ComponentsBuilder using builder: () -> Component) -> Entity { - self.createEntity(with: builder()) + createEntity(with: builder()) } /// Create an entity assigning multiple components. @@ -55,7 +55,7 @@ extension Nexus { /// - Returns: The newly created entity with the provided components assigned. @discardableResult public func createEntity(@ComponentsBuilder using builder: () -> [Component]) -> Entity { - self.createEntity(with: builder()) + createEntity(with: builder()) } /// Create multiple entities assigning one component each. @@ -72,7 +72,7 @@ extension Nexus { /// - Returns: The newly created entities with the provided component assigned. @discardableResult public func createEntities(count: Int, @ComponentsBuilder using builder: (ComponentsBuilder.Context) -> Component) -> [Entity] { - (0.. [Component] = { _ in [] }) -> [Entity] { - (0..(with components: C) -> Entity where C: Collection, C.Element == Component { - let entity = self.createEntity() + public func createEntity(with components: some Collection) -> Entity { + let entity = createEntity() assign(components: components, to: entity.identifier) return entity } @@ -50,7 +50,7 @@ extension Nexus { @discardableResult public func destroy(entity: Entity) -> Bool { - self.destroy(entityId: entity.identifier) + destroy(entityId: entity.identifier) } @discardableResult @@ -76,6 +76,7 @@ extension Nexus { } // MARK: - entities iterator + extension Nexus { public struct EntitiesIterator: IteratorProtocol { private var iterator: AnyIterator @@ -96,5 +97,6 @@ extension Nexus { } } } -extension Nexus.EntitiesIterator: LazySequenceProtocol { } -extension Nexus.EntitiesIterator: Sequence { } + +extension Nexus.EntitiesIterator: LazySequenceProtocol {} +extension Nexus.EntitiesIterator: Sequence {} diff --git a/Sources/FirebladeECS/Nexus+Internal.swift b/Sources/FirebladeECS/Nexus+Internal.swift index 8feafa0f..b3873038 100644 --- a/Sources/FirebladeECS/Nexus+Internal.swift +++ b/Sources/FirebladeECS/Nexus+Internal.swift @@ -8,7 +8,7 @@ extension Nexus { @usableFromInline @discardableResult - func assign(components: C, to entityId: EntityIdentifier) -> Bool where C: Collection, C.Element == Component { + func assign(components: some Collection, to entityId: EntityIdentifier) -> Bool { var iter = components.makeIterator() while let component = iter.next() { let componentId = component.identifier @@ -103,8 +103,8 @@ extension Nexus { return } - let isMember: Bool = self.isMember(entity: entityId, inFamilyWithTraits: traits) - if !exists(entity: entityId) && isMember { + let isMember: Bool = isMember(entity: entityId, inFamilyWithTraits: traits) + if !exists(entity: entityId), isMember { remove(entityWithId: entityId, fromFamilyWithTraits: traits) return } diff --git a/Sources/FirebladeECS/Nexus.swift b/Sources/FirebladeECS/Nexus.swift index 8f7c7f3a..554d84af 100644 --- a/Sources/FirebladeECS/Nexus.swift +++ b/Sources/FirebladeECS/Nexus.swift @@ -42,13 +42,14 @@ public final class Nexus { codingStrategy: DefaultCodingStrategy()) } - internal init(componentsByType: [ComponentIdentifier: ManagedContiguousArray], - componentsByEntity: [EntityIdentifier: Set], - entityIdGenerator: EntityIdentifierGenerator, - familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet], - codingStrategy: CodingStrategy) { + init(componentsByType: [ComponentIdentifier: ManagedContiguousArray], + componentsByEntity: [EntityIdentifier: Set], + entityIdGenerator: EntityIdentifierGenerator, + familyMembersByTraits: [FamilyTraitSet: UnorderedSparseSet], + codingStrategy: CodingStrategy) + { self.componentsByType = componentsByType - self.componentIdsByEntity = componentsByEntity + componentIdsByEntity = componentsByEntity self.familyMembersByTraits = familyMembersByTraits self.entityIdGenerator = entityIdGenerator self.codingStrategy = codingStrategy @@ -66,6 +67,7 @@ public final class Nexus { } // MARK: - CustomDebugStringConvertible + extension Nexus: CustomDebugStringConvertible { public var debugDescription: String { "" @@ -73,8 +75,9 @@ extension Nexus: CustomDebugStringConvertible { } // MARK: - default coding strategy + public struct DefaultCodingStrategy: CodingStrategy { - public init() { } + public init() {} public func codingKey(for componentType: C.Type) -> DynamicCodingKey where C: Component { DynamicCodingKey(stringValue: "\(C.self)").unsafelyUnwrapped diff --git a/Sources/FirebladeECS/NexusEvent.swift b/Sources/FirebladeECS/NexusEvent.swift index 7bc7b380..555effca 100644 --- a/Sources/FirebladeECS/NexusEvent.swift +++ b/Sources/FirebladeECS/NexusEvent.swift @@ -1,5 +1,5 @@ // -// NexusEvents.swift +// NexusEvent.swift // FirebladeECS // // Created by Christian Treffs on 08.10.17. diff --git a/Sources/FirebladeECS/Single.swift b/Sources/FirebladeECS/Single.swift index 36d2c8e8..2d649367 100644 --- a/Sources/FirebladeECS/Single.swift +++ b/Sources/FirebladeECS/Single.swift @@ -32,13 +32,13 @@ extension Single where A: SingleComponent { } public var entity: Entity { - Entity(nexus: self.nexus, id: entityId) + Entity(nexus: nexus, id: entityId) } } extension Nexus { public func single(_ component: S.Type) -> Single where S: SingleComponent { - let family = self.family(requires: S.self) + let family = family(requires: S.self) precondition(family.count <= 1, "Singleton count of \(S.self) must be 0 or 1: \(family.count)") let entityId: EntityIdentifier if family.isEmpty { diff --git a/Sources/FirebladeECS/UnorderedSparseSet.swift b/Sources/FirebladeECS/UnorderedSparseSet.swift index dc6fd79d..7999b5a7 100644 --- a/Sources/FirebladeECS/UnorderedSparseSet.swift +++ b/Sources/FirebladeECS/UnorderedSparseSet.swift @@ -74,7 +74,7 @@ public struct UnorderedSparseSet { guard let denseIndex = findIndex(at: key) else { return nil } - let entry = self.dense[denseIndex] + let entry = dense[denseIndex] assert(entry.key == key, "entry.key and findIndex(at: key) must be equal!") return entry.element } @@ -99,7 +99,7 @@ public struct UnorderedSparseSet { } let removed = swapRemove(at: denseIndex) - if !dense.isEmpty && denseIndex < dense.count { + if !dense.isEmpty, denseIndex < dense.count { let swappedElement = dense[denseIndex] sparse[swappedElement.key] = denseIndex } @@ -208,12 +208,14 @@ extension UnorderedSparseSet where Key == Int { } // MARK: - Sequence + extension UnorderedSparseSet: Sequence { public func makeIterator() -> ElementIterator { ElementIterator(self) } // MARK: - UnorderedSparseSetIterator + public struct ElementIterator: IteratorProtocol { var iterator: IndexingIterator> @@ -226,17 +228,20 @@ extension UnorderedSparseSet: Sequence { } } } -extension UnorderedSparseSet.ElementIterator: LazySequenceProtocol { } -extension UnorderedSparseSet.ElementIterator: Sequence { } + +extension UnorderedSparseSet.ElementIterator: LazySequenceProtocol {} +extension UnorderedSparseSet.ElementIterator: Sequence {} // MARK: - Equatable -extension UnorderedSparseSet.Storage.Entry: Equatable where Element: Equatable { } + +extension UnorderedSparseSet.Storage.Entry: Equatable where Element: Equatable {} extension UnorderedSparseSet.Storage: Equatable where Element: Equatable { @usableFromInline static func == (lhs: UnorderedSparseSet.Storage, rhs: UnorderedSparseSet.Storage) -> Bool { lhs.dense == rhs.dense && lhs.sparse == rhs.sparse } } + extension UnorderedSparseSet: Equatable where Element: Equatable { public static func == (lhs: UnorderedSparseSet, rhs: UnorderedSparseSet) -> Bool { lhs.storage == rhs.storage @@ -244,6 +249,7 @@ extension UnorderedSparseSet: Equatable where Element: Equatable { } // MARK: - Codable -extension UnorderedSparseSet.Storage.Entry: Codable where Element: Codable { } -extension UnorderedSparseSet.Storage: Codable where Element: Codable { } -extension UnorderedSparseSet: Codable where Element: Codable { } + +extension UnorderedSparseSet.Storage.Entry: Codable where Element: Codable {} +extension UnorderedSparseSet.Storage: Codable where Element: Codable {} +extension UnorderedSparseSet: Codable where Element: Codable {} diff --git a/Tests/FirebladeECSPerformanceTests/HashingPerformanceTests.swift b/Tests/FirebladeECSPerformanceTests/HashingPerformanceTests.swift index 8446ebf7..5b64f5ec 100644 --- a/Tests/FirebladeECSPerformanceTests/HashingPerformanceTests.swift +++ b/Tests/FirebladeECSPerformanceTests/HashingPerformanceTests.swift @@ -5,6 +5,7 @@ // Created by Christian Treffs on 14.02.19. // +#if os(macOS) import FirebladeECS import XCTest @@ -97,3 +98,6 @@ class HashingPerformanceTests: XCTestCase { #endif } } +#else + #warning("Skipping HashingPerformanceTests") +#endif diff --git a/Tests/FirebladeECSPerformanceTests/TypeIdentifierPerformanceTests.swift b/Tests/FirebladeECSPerformanceTests/TypeIdentifierPerformanceTests.swift index 661ee980..e0731744 100644 --- a/Tests/FirebladeECSPerformanceTests/TypeIdentifierPerformanceTests.swift +++ b/Tests/FirebladeECSPerformanceTests/TypeIdentifierPerformanceTests.swift @@ -5,6 +5,7 @@ // Created by Christian Treffs on 05.10.19. // +#if os(macOS) import FirebladeECS import XCTest @@ -30,7 +31,7 @@ final class TypeIdentifierPerformanceTests: XCTestCase { /// release: 1.034 sec /// debug: func testPerformanceHash() { - measure { + measure(options: .default) { for _ in 0.. [XCTestCaseEntry] { - return [ - testCase(ComponentIdentifierTests.__allTests__ComponentIdentifierTests), - testCase(HashingPerformanceTests.__allTests__HashingPerformanceTests), - testCase(TypeIdentifierPerformanceTests.__allTests__TypeIdentifierPerformanceTests), - testCase(TypedFamilyPerformanceTests.__allTests__TypedFamilyPerformanceTests), - ] -} -#endif diff --git a/Tests/FirebladeECSTests/Generated/FamilyTests.generated.swift b/Tests/FirebladeECSTests/Generated/FamilyTests.generated.swift index 3f0b9882..345fcf9e 100644 --- a/Tests/FirebladeECSTests/Generated/FamilyTests.generated.swift +++ b/Tests/FirebladeECSTests/Generated/FamilyTests.generated.swift @@ -1,6 +1,5 @@ -// Generated using Sourcery 1.0.0 — https://github.com/krzysztofzablocki/Sourcery +// Generated using Sourcery 2.2.5 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT - import FirebladeECS import XCTest diff --git a/Tests/FirebladeECSTests/XCTestManifests.swift b/Tests/FirebladeECSTests/XCTestManifests.swift deleted file mode 100644 index 5b554206..00000000 --- a/Tests/FirebladeECSTests/XCTestManifests.swift +++ /dev/null @@ -1,454 +0,0 @@ -#if !canImport(ObjectiveC) -import XCTest - -extension ComponentIdentifierTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__ComponentIdentifierTests = [ - ("testMirrorAsStableIdentifier", testMirrorAsStableIdentifier), - ("testStringDescribingAsStableIdentifier", testStringDescribingAsStableIdentifier), - ] -} - -extension ComponentInstanceProviderTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__ComponentInstanceProviderTests = [ - ("testProviderReturnsTheInstance", testProviderReturnsTheInstance), - ("testProvidersWithDifferentInstanceHaveDifferentIdentifier", testProvidersWithDifferentInstanceHaveDifferentIdentifier), - ("testProvidersWithSameInstanceHaveSameIdentifier", testProvidersWithSameInstanceHaveSameIdentifier), - ] -} - -extension ComponentSingletonProviderTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__ComponentSingletonProviderTests = [ - ("testProviderReturnsAnInstanceOfType", testProviderReturnsAnInstanceOfType), - ("testProviderReturnsSameInstanceEachTime", testProviderReturnsSameInstanceEachTime), - ("testProvidersWithDifferentTypeHaveDifferentIdentifier", testProvidersWithDifferentTypeHaveDifferentIdentifier), - ("testProvidersWithSameTypeHaveDifferentIdentifier", testProvidersWithSameTypeHaveDifferentIdentifier), - ] -} - -extension ComponentTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__ComponentTests = [ - ("testComponentIdentifier", testComponentIdentifier), - ] -} - -extension ComponentTypeProviderTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__ComponentTypeProviderTests = [ - ("testProviderReturnsAnInstanceOfType", testProviderReturnsAnInstanceOfType), - ("testProviderReturnsNewInstanceEachTime", testProviderReturnsNewInstanceEachTime), - ("testProvidersWithDifferentTypeHaveDifferentIdentifier", testProvidersWithDifferentTypeHaveDifferentIdentifier), - ("testProvidersWithSameTypeHaveSameIdentifier", testProvidersWithSameTypeHaveSameIdentifier), - ] -} - -extension DynamicComponentProviderTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__DynamicComponentProviderTests = [ - ("testProviderReturnsTheInstance", testProviderReturnsTheInstance), - ("testProvidersWithDifferentMethodsHaveDifferentIdentifier", testProvidersWithDifferentMethodsHaveDifferentIdentifier), - ("testProvidersWithSameMethodHaveSameIdentifier", testProvidersWithSameMethodHaveSameIdentifier), - ] -} - -extension EntityCreationTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__EntityCreationTests = [ - ("testBulkCreateEntitiesMultipleComponents", testBulkCreateEntitiesMultipleComponents), - ("testBulkCreateEntitiesOneComponent", testBulkCreateEntitiesOneComponent), - ("testCreateEntityMultipleComponents", testCreateEntityMultipleComponents), - ("testCreateEntityOneComponent", testCreateEntityOneComponent), - ] -} - -extension EntityIdGenTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__EntityIdGenTests = [ - ("testGenerateWithInitialIds", testGenerateWithInitialIds), - ("testGeneratorDefaultInit", testGeneratorDefaultInit), - ("testGeneratorMarkUnused", testGeneratorMarkUnused), - ("testGeneratorWithDefaultEmptyCollection", testGeneratorWithDefaultEmptyCollection), - ("testLinearIncrement", testLinearIncrement), - ] -} - -extension EntityStateMachineTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__EntityStateMachineTests = [ - ("testCallChangeStateWithSameNameLeavesEntityComponentsIntact", testCallChangeStateWithSameNameLeavesEntityComponentsIntact), - ("testCreateStateAddsState", testCreateStateAddsState), - ("testCreateStateDoesNotChangeState", testCreateStateDoesNotChangeState), - ("testEnterSecondStateAddsSecondStatesComponents", testEnterSecondStateAddsSecondStatesComponents), - ("testEnterSecondStateDoesNotRemoveOverlappingComponents", testEnterSecondStateDoesNotRemoveOverlappingComponents), - ("testEnterSecondStateRemovesDifferentComponentsOfSameType", testEnterSecondStateRemovesDifferentComponentsOfSameType), - ("testEnterSecondStateRemovesFirstStatesComponents", testEnterSecondStateRemovesFirstStatesComponents), - ("testEnterStateAddsStatesComponents", testEnterStateAddsStatesComponents), - ("testGetsDeinitedWhileBeingStronglyReferencedByComponentAssignedToEntity", testGetsDeinitedWhileBeingStronglyReferencedByComponentAssignedToEntity), - ] -} - -extension EntityStateTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__EntityStateTests = [ - ("testAddInstanceCreatesMappingAndSetsInstanceProviderForInstanceType", testAddInstanceCreatesMappingAndSetsInstanceProviderForInstanceType), - ("testAddMappingWithInstanceQualifierCreatesInstanceProvider", testAddMappingWithInstanceQualifierCreatesInstanceProvider), - ("testAddMappingWithMethodQualifierCreatesDynamicProvider", testAddMappingWithMethodQualifierCreatesDynamicProvider), - ("testAddMappingWithNoQualifierCreatesTypeProvider", testAddMappingWithNoQualifierCreatesTypeProvider), - ("testAddMappingWithSingletonQualifierCreatesSingletonProvider", testAddMappingWithSingletonQualifierCreatesSingletonProvider), - ("testAddMappingWithTypeQualifierCreatesTypeProvider", testAddMappingWithTypeQualifierCreatesTypeProvider), - ("testAddMethodCreatesMappingAndSetsDynamicProviderForType", testAddMethodCreatesMappingAndSetsDynamicProviderForType), - ("testAddProviderCreatesMappingAndSetsProvider", testAddProviderCreatesMappingAndSetsProvider), - ("testAddSingletonCreatesMappingAndSetsSingletonProviderForType", testAddSingletonCreatesMappingAndSetsSingletonProviderForType), - ("testAddTypeCreatesMappingAndSetsTypeProviderForType", testAddTypeCreatesMappingAndSetsTypeProviderForType), - ("testHasProviderReturnsFalseForNotCreatedProvider", testHasProviderReturnsFalseForNotCreatedProvider), - ("testHasProviderReturnsTrueForCreatedProvider", testHasProviderReturnsTrueForCreatedProvider), - ("testProviderForTypeReturnsDynamicProvider", testProviderForTypeReturnsDynamicProvider), - ("testProviderForTypeReturnsInstanceProvider", testProviderForTypeReturnsInstanceProvider), - ("testProviderForTypeReturnsPassedProvider", testProviderForTypeReturnsPassedProvider), - ("testProviderForTypeReturnsSingletonProvider", testProviderForTypeReturnsSingletonProvider), - ("testProviderForTypeReturnsTypeProvider", testProviderForTypeReturnsTypeProvider), - ("testProviderForTypeReturnsTypeProviderByDefault", testProviderForTypeReturnsTypeProviderByDefault), - ] -} - -extension EntityTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__EntityTests = [ - ("testAllComponentsOfEntity", testAllComponentsOfEntity), - ("testComponentsIteration", testComponentsIteration), - ("testEntityCreationIntrinsic", testEntityCreationIntrinsic), - ("testEntityDescriptions", testEntityDescriptions), - ("testEntityEquality", testEntityEquality), - ("testEntityIdentifierAndIndex", testEntityIdentifierAndIndex), - ("testEntityIdGenerator", testEntityIdGenerator), - ("testEntitySubscripts", testEntitySubscripts), - ("testRemoveAllComponentsFromEntity", testRemoveAllComponentsFromEntity), - ] -} - -extension Family1Tests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Family1Tests = [ - ("testComponentIteration", testComponentIteration), - ("testEntityComponentIteration", testEntityComponentIteration), - ("testEntityIteration", testEntityIteration), - ("testFamilyDecoding", testFamilyDecoding), - ("testFamilyEncoding", testFamilyEncoding), - ("testFamilyFailDecoding", testFamilyFailDecoding), - ("testMemberCreation", testMemberCreation), - ("testMemberCreationBuilder", testMemberCreationBuilder), - ] -} - -extension Family2Tests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Family2Tests = [ - ("testComponentIteration", testComponentIteration), - ("testEntityComponentIteration", testEntityComponentIteration), - ("testEntityIteration", testEntityIteration), - ("testFamilyDecoding", testFamilyDecoding), - ("testFamilyEncoding", testFamilyEncoding), - ("testFamilyFailDecoding", testFamilyFailDecoding), - ("testMemberCreation", testMemberCreation), - ("testMemberCreationBuilder", testMemberCreationBuilder), - ] -} - -extension Family3Tests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Family3Tests = [ - ("testComponentIteration", testComponentIteration), - ("testEntityComponentIteration", testEntityComponentIteration), - ("testEntityIteration", testEntityIteration), - ("testFamilyDecoding", testFamilyDecoding), - ("testFamilyEncoding", testFamilyEncoding), - ("testFamilyFailDecoding", testFamilyFailDecoding), - ("testMemberCreation", testMemberCreation), - ("testMemberCreationBuilder", testMemberCreationBuilder), - ] -} - -extension Family4Tests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Family4Tests = [ - ("testComponentIteration", testComponentIteration), - ("testEntityComponentIteration", testEntityComponentIteration), - ("testEntityIteration", testEntityIteration), - ("testFamilyDecoding", testFamilyDecoding), - ("testFamilyEncoding", testFamilyEncoding), - ("testFamilyFailDecoding", testFamilyFailDecoding), - ("testMemberCreation", testMemberCreation), - ("testMemberCreationBuilder", testMemberCreationBuilder), - ] -} - -extension Family5Tests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Family5Tests = [ - ("testComponentIteration", testComponentIteration), - ("testEntityComponentIteration", testEntityComponentIteration), - ("testEntityIteration", testEntityIteration), - ("testFamilyDecoding", testFamilyDecoding), - ("testFamilyEncoding", testFamilyEncoding), - ("testFamilyFailDecoding", testFamilyFailDecoding), - ("testMemberCreation", testMemberCreation), - ("testMemberCreationBuilder", testMemberCreationBuilder), - ] -} - -extension Family6Tests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Family6Tests = [ - ("testComponentIteration", testComponentIteration), - ("testEntityComponentIteration", testEntityComponentIteration), - ("testEntityIteration", testEntityIteration), - ("testFamilyDecoding", testFamilyDecoding), - ("testFamilyEncoding", testFamilyEncoding), - ("testFamilyFailDecoding", testFamilyFailDecoding), - ("testMemberCreation", testMemberCreation), - ("testMemberCreationBuilder", testMemberCreationBuilder), - ] -} - -extension Family7Tests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Family7Tests = [ - ("testComponentIteration", testComponentIteration), - ("testEntityComponentIteration", testEntityComponentIteration), - ("testEntityIteration", testEntityIteration), - ("testFamilyDecoding", testFamilyDecoding), - ("testFamilyEncoding", testFamilyEncoding), - ("testFamilyFailDecoding", testFamilyFailDecoding), - ("testMemberCreation", testMemberCreation), - ("testMemberCreationBuilder", testMemberCreationBuilder), - ] -} - -extension Family8Tests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__Family8Tests = [ - ("testComponentIteration", testComponentIteration), - ("testEntityComponentIteration", testEntityComponentIteration), - ("testEntityIteration", testEntityIteration), - ("testFamilyDecoding", testFamilyDecoding), - ("testFamilyEncoding", testFamilyEncoding), - ("testFamilyFailDecoding", testFamilyFailDecoding), - ("testMemberCreation", testMemberCreation), - ("testMemberCreationBuilder", testMemberCreationBuilder), - ] -} - -extension FamilyCodingTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__FamilyCodingTests = [ - ("testDecodeFamily4", testDecodeFamily4), - ("testDecodeFamily5", testDecodeFamily5), - ("testDecodingFamily1", testDecodingFamily1), - ("testDecodingFamily2", testDecodingFamily2), - ("testDecodingFamily3", testDecodingFamily3), - ("testEncodeFamily2", testEncodeFamily2), - ("testEncodeFamily3", testEncodeFamily3), - ("testEncodeFamily4", testEncodeFamily4), - ("testEncodeFamily5", testEncodeFamily5), - ("testEncodingFamily1", testEncodingFamily1), - ("testFailDecodingFamily", testFailDecodingFamily), - ] -} - -extension FamilyTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__FamilyTests = [ - ("testFamilyAbandoned", testFamilyAbandoned), - ("testFamilyBulkDestroy", testFamilyBulkDestroy), - ("testFamilyCreateMembers", testFamilyCreateMembers), - ("testFamilyCreation", testFamilyCreation), - ("testFamilyDestroyMembers", testFamilyDestroyMembers), - ("testFamilyExchange", testFamilyExchange), - ("testFamilyLateMember", testFamilyLateMember), - ("testFamilyMemberBasicIteration", testFamilyMemberBasicIteration), - ("testFamilyReuse", testFamilyReuse), - ] -} - -extension FamilyTraitsTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__FamilyTraitsTests = [ - ("testTraitCommutativity", testTraitCommutativity), - ("testTraitMatching", testTraitMatching), - ] -} - -extension HashingTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__HashingTests = [ - ("testCollisionsInCritialRange", testCollisionsInCritialRange), - ("testStringHashes", testStringHashes), - ] -} - -extension NexusEventDelegateTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__NexusEventDelegateTests = [ - ("testEventComponentAdded", testEventComponentAdded), - ("testEventComponentRemoved", testEventComponentRemoved), - ("testEventEntityCreated", testEventEntityCreated), - ("testEventEntityDestroyed", testEventEntityDestroyed), - ("testFamilyMemberRemoved", testFamilyMemberRemoved), - ("testFamilyMemeberAdded", testFamilyMemeberAdded), - ] -} - -extension NexusTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__NexusTests = [ - ("testComponentCreation", testComponentCreation), - ("testComponentDeletion", testComponentDeletion), - ("testComponentRetrieval", testComponentRetrieval), - ("testComponentUniqueness", testComponentUniqueness), - ("testEntityCreate", testEntityCreate), - ("testEntityDestroy", testEntityDestroy), - ("testEntityIteration", testEntityIteration), - ] -} - -extension SingleTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__SingleTests = [ - ("testSingleCreation", testSingleCreation), - ("testSingleCreationOnExistingFamilyMember", testSingleCreationOnExistingFamilyMember), - ("testSingleEntityAndComponentCreation", testSingleEntityAndComponentCreation), - ("testSingleReuse", testSingleReuse), - ] -} - -extension SparseSetTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__SparseSetTests = [ - ("testAlternativeKey", testAlternativeKey), - ("testEquality", testEquality), - ("testSparseSetAdd", testSparseSetAdd), - ("testSparseSetAddAndReplace", testSparseSetAddAndReplace), - ("testSparseSetClear", testSparseSetClear), - ("testSparseSetDoubleRemove", testSparseSetDoubleRemove), - ("testSparseSetGet", testSparseSetGet), - ("testSparseSetNonCongiuousData", testSparseSetNonCongiuousData), - ("testSparseSetReduce", testSparseSetReduce), - ("testSparseSetRemove", testSparseSetRemove), - ("testSparseSetRemoveAndAdd", testSparseSetRemoveAndAdd), - ("testSparseSetRemoveNonPresent", testSparseSetRemoveNonPresent), - ("testStartEndIndex", testStartEndIndex), - ("testSubscript", testSubscript), - ] -} - -extension StateComponentMappingTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__StateComponentMappingTests = [ - ("testAddAddsProviderToState", testAddAddsProviderToState), - ("testAddReturnsSameMappingForDifferentComponentTypes", testAddReturnsSameMappingForDifferentComponentTypes), - ("testAddReturnsSameMappingForSameComponentType", testAddReturnsSameMappingForSameComponentType), - ] -} - -extension SystemsTests { - // DO NOT MODIFY: This is autogenerated, use: - // `swift test --generate-linuxmain` - // to regenerate. - static let __allTests__SystemsTests = [ - ("testSystemsUpdate", testSystemsUpdate), - ] -} - -public func __allTests() -> [XCTestCaseEntry] { - return [ - testCase(ComponentIdentifierTests.__allTests__ComponentIdentifierTests), - testCase(ComponentInstanceProviderTests.__allTests__ComponentInstanceProviderTests), - testCase(ComponentSingletonProviderTests.__allTests__ComponentSingletonProviderTests), - testCase(ComponentTests.__allTests__ComponentTests), - testCase(ComponentTypeProviderTests.__allTests__ComponentTypeProviderTests), - testCase(DynamicComponentProviderTests.__allTests__DynamicComponentProviderTests), - testCase(EntityCreationTests.__allTests__EntityCreationTests), - testCase(EntityIdGenTests.__allTests__EntityIdGenTests), - testCase(EntityStateMachineTests.__allTests__EntityStateMachineTests), - testCase(EntityStateTests.__allTests__EntityStateTests), - testCase(EntityTests.__allTests__EntityTests), - testCase(Family1Tests.__allTests__Family1Tests), - testCase(Family2Tests.__allTests__Family2Tests), - testCase(Family3Tests.__allTests__Family3Tests), - testCase(Family4Tests.__allTests__Family4Tests), - testCase(Family5Tests.__allTests__Family5Tests), - testCase(Family6Tests.__allTests__Family6Tests), - testCase(Family7Tests.__allTests__Family7Tests), - testCase(Family8Tests.__allTests__Family8Tests), - testCase(FamilyCodingTests.__allTests__FamilyCodingTests), - testCase(FamilyTests.__allTests__FamilyTests), - testCase(FamilyTraitsTests.__allTests__FamilyTraitsTests), - testCase(HashingTests.__allTests__HashingTests), - testCase(NexusEventDelegateTests.__allTests__NexusEventDelegateTests), - testCase(NexusTests.__allTests__NexusTests), - testCase(SingleTests.__allTests__SingleTests), - testCase(SparseSetTests.__allTests__SparseSetTests), - testCase(StateComponentMappingTests.__allTests__StateComponentMappingTests), - testCase(SystemsTests.__allTests__SystemsTests), - ] -} -#endif diff --git a/Tests/LinuxMain.swift b/Tests/LinuxMain.swift deleted file mode 100644 index 7889cf46..00000000 --- a/Tests/LinuxMain.swift +++ /dev/null @@ -1,10 +0,0 @@ -import XCTest - -import FirebladeECSPerformanceTests -import FirebladeECSTests - -var tests = [XCTestCaseEntry]() -tests += FirebladeECSPerformanceTests.__allTests() -tests += FirebladeECSTests.__allTests() - -XCTMain(tests) diff --git a/renovate.json b/renovate.json new file mode 100644 index 00000000..e6838fd6 --- /dev/null +++ b/renovate.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["config:base"], + "packageRules": [ + { + "description": "Accumulate non-major updates into one pull request", + "matchUpdateTypes": ["minor", "patch"], + "matchCurrentVersion": ">=1", + "groupName": "all non-major dependencies", + "groupSlug": "all-minor-patch" + } + ] +}