From 139e6c23a0cf717d5ede2a72e0d45f8318075392 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Tue, 4 Aug 2020 11:57:12 +0200 Subject: [PATCH 01/21] Add setupEnvironment to Makefile --- Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index aaa0d8b..77ad178 100644 --- a/Makefile +++ b/Makefile @@ -53,4 +53,10 @@ cleanArtifacts: # Test links in README # requires testReadme: - markdown-link-check -p -v ./README.md \ No newline at end of file + markdown-link-check -p -v ./README.md + +setupEnvironment: + brew update + brew install swiftenv + brew install swiftlint + brew install sourcery From f08c3f8ba9b76f78bfb8bc2e31f0f4e8c422f01b Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Tue, 4 Aug 2020 13:05:34 +0200 Subject: [PATCH 02/21] Setup sourcery generation --- .sourcery.yml | 6 ++++++ Makefile | 3 +++ Sources/FirebladeECS/Generated/.gitkeep | 0 Sources/FirebladeECS/Generated/Family.generated.swift | 6 ++++++ Sources/FirebladeECS/Stencils/Family.stencil | 3 +++ 5 files changed, 18 insertions(+) create mode 100644 .sourcery.yml create mode 100644 Sources/FirebladeECS/Generated/.gitkeep create mode 100644 Sources/FirebladeECS/Generated/Family.generated.swift create mode 100644 Sources/FirebladeECS/Stencils/Family.stencil diff --git a/.sourcery.yml b/.sourcery.yml new file mode 100644 index 0000000..8daf1cb --- /dev/null +++ b/.sourcery.yml @@ -0,0 +1,6 @@ +sources: # you can provide either single path or several paths using `-` + - Sources +templates: # as well as for templates + - Sources/FirebladeECS/Stencils +output: # note that there is no `-` here as only single output path is supported + Sources/FirebladeECS/Generated diff --git a/Makefile b/Makefile index 77ad178..758aad2 100644 --- a/Makefile +++ b/Makefile @@ -60,3 +60,6 @@ setupEnvironment: brew install swiftenv brew install swiftlint brew install sourcery + +generateCode: + sourcery \ No newline at end of file diff --git a/Sources/FirebladeECS/Generated/.gitkeep b/Sources/FirebladeECS/Generated/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Sources/FirebladeECS/Generated/Family.generated.swift b/Sources/FirebladeECS/Generated/Family.generated.swift new file mode 100644 index 0000000..5ef4cf6 --- /dev/null +++ b/Sources/FirebladeECS/Generated/Family.generated.swift @@ -0,0 +1,6 @@ +// Generated using Sourcery 0.18.0 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT + +// swiftlint:disable line_length +// swiftlint:disable variable_name + diff --git a/Sources/FirebladeECS/Stencils/Family.stencil b/Sources/FirebladeECS/Stencils/Family.stencil new file mode 100644 index 0000000..023ec9a --- /dev/null +++ b/Sources/FirebladeECS/Stencils/Family.stencil @@ -0,0 +1,3 @@ +// swiftlint:disable line_length +// swiftlint:disable variable_name + From c53952615ab566b144349c748d2bc8f1ecb910f3 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Tue, 4 Aug 2020 15:37:31 +0200 Subject: [PATCH 03/21] Stencil WIP --- Makefile | 2 +- Package.swift | 3 +- Sources/FirebladeECS/Family1.swift | 60 ----------- Sources/FirebladeECS/Family2.swift | 72 ------------- Sources/FirebladeECS/Family3.swift | 79 -------------- Sources/FirebladeECS/Family4.swift | 87 --------------- Sources/FirebladeECS/Family5.swift | 96 ----------------- Sources/FirebladeECS/Stencils/Family.stencil | 105 +++++++++++++++++++ 8 files changed, 108 insertions(+), 396 deletions(-) delete mode 100644 Sources/FirebladeECS/Family1.swift delete mode 100644 Sources/FirebladeECS/Family2.swift delete mode 100644 Sources/FirebladeECS/Family3.swift delete mode 100644 Sources/FirebladeECS/Family4.swift delete mode 100644 Sources/FirebladeECS/Family5.swift diff --git a/Makefile b/Makefile index 758aad2..8077b48 100644 --- a/Makefile +++ b/Makefile @@ -62,4 +62,4 @@ setupEnvironment: brew install sourcery generateCode: - sourcery \ No newline at end of file + sourcery --verbose \ No newline at end of file diff --git a/Package.swift b/Package.swift index 36f03a2..e7ac6b8 100644 --- a/Package.swift +++ b/Package.swift @@ -8,7 +8,8 @@ let package = Package( targets: ["FirebladeECS"]) ], targets: [ - .target(name: "FirebladeECS"), + .target(name: "FirebladeECS", + exclude: ["Stencils"]), .testTarget(name: "FirebladeECSTests", dependencies: ["FirebladeECS"]), .testTarget(name: "FirebladeECSPerformanceTests", diff --git a/Sources/FirebladeECS/Family1.swift b/Sources/FirebladeECS/Family1.swift deleted file mode 100644 index 344e36f..0000000 --- a/Sources/FirebladeECS/Family1.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// Family1.swift -// -// -// Created by Christian Treffs on 21.08.19. -// - -public typealias Family1 = Family> - -public struct Requires1: FamilyRequirementsManaging where A: Component { - public let componentTypes: [Component.Type] - - public init(_ components: A.Type) { - componentTypes = [A.self] - } - - public static func components(nexus: Nexus, entityId: EntityIdentifier) -> A { - let compA: A = nexus.get(unsafeComponentFor: entityId) - return (compA) - } - - public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, A) { - let entity: Entity = nexus.get(unsafeEntity: entityId) - let compA: A = nexus.get(unsafeComponentFor: entityId) - return (entity, compA) - } - - public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: A, child: A) { - let parentCompA: A = nexus.get(unsafeComponentFor: parentId) - let childCompA: A = nexus.get(unsafeComponentFor: childId) - return (parent: parentCompA, child: childCompA) - } - - public static func createMember(nexus: Nexus, components: A) -> Entity { - nexus.createEntity(with: components) - } -} - -extension Requires1: FamilyDecoding where A: Decodable { - public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> A { - try container.decode(A.self, forKey: strategy.codingKey(for: A.self)) - } -} - -extension Requires1: FamilyEncoding where A: Encodable { - public static func encode(components: Components, into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { - try container.encode(components, forKey: strategy.codingKey(for: A.self)) - } -} - -extension Nexus { - public func family( - requires componentA: A.Type, - excludesAll excludedComponents: Component.Type... - ) -> Family1 where A: Component { - Family1(nexus: self, - requiresAll: componentA, - excludesAll: excludedComponents) - } -} diff --git a/Sources/FirebladeECS/Family2.swift b/Sources/FirebladeECS/Family2.swift deleted file mode 100644 index 1f1e58e..0000000 --- a/Sources/FirebladeECS/Family2.swift +++ /dev/null @@ -1,72 +0,0 @@ -// -// Family2.swift -// -// -// Created by Christian Treffs on 21.08.19. -// - -// swiftlint:disable large_tuple - -public typealias Family2 = Family> - -public struct Requires2: FamilyRequirementsManaging where A: Component, B: Component { - public let componentTypes: [Component.Type] - - public init(_ components: (A.Type, B.Type)) { - componentTypes = [ A.self, B.self] - } - - public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (A, B) { - let compA: A = nexus.get(unsafeComponentFor: entityId) - let compB: B = nexus.get(unsafeComponentFor: entityId) - return (compA, compB) - } - - public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, A, B) { - let entity: Entity = nexus.get(unsafeEntity: entityId) - let compA: A = nexus.get(unsafeComponentFor: entityId) - let compB: B = nexus.get(unsafeComponentFor: entityId) - return (entity, compA, compB) - } - - public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (A, B), child: (A, B)) { - let pcA: A = nexus.get(unsafeComponentFor: parentId) - let pcB: B = nexus.get(unsafeComponentFor: parentId) - let ccA: A = nexus.get(unsafeComponentFor: childId) - let ccB: B = nexus.get(unsafeComponentFor: childId) - return (parent: (pcA, pcB), child: (ccA, ccB)) - } - - public static func createMember(nexus: Nexus, components: (A, B)) -> Entity { - nexus.createEntity(with: components.0, components.1) - } -} - -extension Requires2: FamilyEncoding where A: Encodable, B: Encodable { - public static func encode(components: (A, B), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { - try container.encode(components.0, forKey: strategy.codingKey(for: A.self)) - try container.encode(components.1, forKey: strategy.codingKey(for: B.self)) - } -} - -extension Requires2: FamilyDecoding where A: Decodable, B: Decodable { - public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (A, B) { - let compA = try container.decode(A.self, forKey: strategy.codingKey(for: A.self)) - let compB = try container.decode(B.self, forKey: strategy.codingKey(for: B.self)) - return Components(compA, compB) - } -} - -extension Nexus { - public func family( - requiresAll componentA: A.Type, - _ componentB: B.Type, - excludesAll excludedComponents: Component.Type... - ) -> Family2 where A: Component, B: Component { - Family2( - nexus: self, - requiresAll: (componentA, componentB), - excludesAll: excludedComponents - ) - } -} diff --git a/Sources/FirebladeECS/Family3.swift b/Sources/FirebladeECS/Family3.swift deleted file mode 100644 index a244a58..0000000 --- a/Sources/FirebladeECS/Family3.swift +++ /dev/null @@ -1,79 +0,0 @@ -// -// Family3.swift -// -// -// Created by Christian Treffs on 21.08.19. -// - -// swiftlint:disable large_tuple - -public typealias Family3 = Family> - -public struct Requires3: FamilyRequirementsManaging where A: Component, B: Component, C: Component { - public let componentTypes: [Component.Type] - - public init(_ types: (A.Type, B.Type, C.Type)) { - componentTypes = [A.self, B.self, C.self] - } - - public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (A, B, C) { - let compA: A = nexus.get(unsafeComponentFor: entityId) - let compB: B = nexus.get(unsafeComponentFor: entityId) - let compC: C = nexus.get(unsafeComponentFor: entityId) - return (compA, compB, compC) - } - - public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, A, B, C) { - let entity: Entity = nexus.get(unsafeEntity: entityId) - let compA: A = nexus.get(unsafeComponentFor: entityId) - let compB: B = nexus.get(unsafeComponentFor: entityId) - let compC: C = nexus.get(unsafeComponentFor: entityId) - return (entity, compA, compB, compC) - } - public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> - (parent: (A, B, C), child: (A, B, C)) { - let pcA: A = nexus.get(unsafeComponentFor: parentId) - let pcB: B = nexus.get(unsafeComponentFor: parentId) - let pcC: C = nexus.get(unsafeComponentFor: parentId) - let ccA: A = nexus.get(unsafeComponentFor: childId) - let ccB: B = nexus.get(unsafeComponentFor: childId) - let ccC: C = nexus.get(unsafeComponentFor: childId) - return (parent: (pcA, pcB, pcC), child: (ccA, ccB, ccC)) - } - - public static func createMember(nexus: Nexus, components: (A, B, C)) -> Entity { - nexus.createEntity(with: components.0, components.1, components.2) - } -} - -extension Requires3: FamilyEncoding where A: Encodable, B: Encodable, C: Encodable { - public static func encode(components: (A, B, C), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { - try container.encode(components.0, forKey: strategy.codingKey(for: A.self)) - try container.encode(components.1, forKey: strategy.codingKey(for: B.self)) - try container.encode(components.2, forKey: strategy.codingKey(for: C.self)) - } -} - -extension Requires3: FamilyDecoding where A: Decodable, B: Decodable, C: Decodable { - public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (A, B, C) { - let compA = try container.decode(A.self, forKey: strategy.codingKey(for: A.self)) - let compB = try container.decode(B.self, forKey: strategy.codingKey(for: B.self)) - let compC = try container.decode(C.self, forKey: strategy.codingKey(for: C.self)) - return Components(compA, compB, compC) - } -} - -extension Nexus { - public func family( - requiresAll componentA: A.Type, - _ componentB: B.Type, - _ componentC: C.Type, - excludesAll excludedComponents: Component.Type... - ) -> Family3 where A: Component, B: Component, C: Component { - Family3( - nexus: self, - requiresAll: (componentA, componentB, componentC), - excludesAll: excludedComponents - ) - } -} diff --git a/Sources/FirebladeECS/Family4.swift b/Sources/FirebladeECS/Family4.swift deleted file mode 100644 index ec9e40d..0000000 --- a/Sources/FirebladeECS/Family4.swift +++ /dev/null @@ -1,87 +0,0 @@ -// -// Family4.swift -// -// -// Created by Christian Treffs on 21.08.19. -// - -// swiftlint:disable large_tuple - -public typealias Family4 = Family> - -public struct Requires4: FamilyRequirementsManaging where A: Component, B: Component, C: Component, D: Component { - public let componentTypes: [Component.Type] - - public init(_ types: (A.Type, B.Type, C.Type, D.Type)) { - componentTypes = [A.self, B.self, C.self, D.self] - } - - public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (A, B, C, D) { - let compA: A = nexus.get(unsafeComponentFor: entityId) - let compB: B = nexus.get(unsafeComponentFor: entityId) - let compC: C = nexus.get(unsafeComponentFor: entityId) - let compD: D = nexus.get(unsafeComponentFor: entityId) - return (compA, compB, compC, compD) - } - - public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, A, B, C, D) { - let entity: Entity = nexus.get(unsafeEntity: entityId) - let compA: A = nexus.get(unsafeComponentFor: entityId) - let compB: B = nexus.get(unsafeComponentFor: entityId) - let compC: C = nexus.get(unsafeComponentFor: entityId) - let compD: D = nexus.get(unsafeComponentFor: entityId) - return (entity, compA, compB, compC, compD) - } - - public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> - (parent: (A, B, C, D), child: (A, B, C, D)) { - let pcA: A = nexus.get(unsafeComponentFor: parentId) - let pcB: B = nexus.get(unsafeComponentFor: parentId) - let pcC: C = nexus.get(unsafeComponentFor: parentId) - let pcD: D = nexus.get(unsafeComponentFor: parentId) - let ccA: A = nexus.get(unsafeComponentFor: childId) - let ccB: B = nexus.get(unsafeComponentFor: childId) - let ccC: C = nexus.get(unsafeComponentFor: childId) - let ccD: D = nexus.get(unsafeComponentFor: childId) - return (parent: (pcA, pcB, pcC, pcD), child: (ccA, ccB, ccC, ccD)) - } - - public static func createMember(nexus: Nexus, components: (A, B, C, D)) -> Entity { - nexus.createEntity(with: components.0, components.1, components.2, components.3) - } -} - -extension Requires4: FamilyEncoding where A: Encodable, B: Encodable, C: Encodable, D: Encodable { - public static func encode(components: (A, B, C, D), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { - try container.encode(components.0, forKey: strategy.codingKey(for: A.self)) - try container.encode(components.1, forKey: strategy.codingKey(for: B.self)) - try container.encode(components.2, forKey: strategy.codingKey(for: C.self)) - try container.encode(components.3, forKey: strategy.codingKey(for: D.self)) - } -} - -extension Requires4: FamilyDecoding where A: Decodable, B: Decodable, C: Decodable, D: Decodable { - public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (A, B, C, D) { - let compA = try container.decode(A.self, forKey: strategy.codingKey(for: A.self)) - let compB = try container.decode(B.self, forKey: strategy.codingKey(for: B.self)) - let compC = try container.decode(C.self, forKey: strategy.codingKey(for: C.self)) - let compD = try container.decode(D.self, forKey: strategy.codingKey(for: D.self)) - return Components(compA, compB, compC, compD) - } -} - -extension Nexus { - public func family( - requiresAll componentA: A.Type, - _ componentB: B.Type, - _ componentC: C.Type, - _ componentD: D.Type, - excludesAll excludedComponents: Component.Type... - ) -> Family4 where A: Component, B: Component, C: Component, D: Component { - Family4( - nexus: self, - requiresAll: (componentA, componentB, componentC, componentD), - excludesAll: excludedComponents - ) - } -} diff --git a/Sources/FirebladeECS/Family5.swift b/Sources/FirebladeECS/Family5.swift deleted file mode 100644 index 6bbf9e2..0000000 --- a/Sources/FirebladeECS/Family5.swift +++ /dev/null @@ -1,96 +0,0 @@ -// -// Family5.swift -// -// -// Created by Christian Treffs on 21.08.19. -// - -// swiftlint:disable large_tuple - -public typealias Family5 = Family> - -public struct Requires5: FamilyRequirementsManaging where A: Component, B: Component, C: Component, D: Component, E: Component { - public let componentTypes: [Component.Type] - - public init(_ types: (A.Type, B.Type, C.Type, D.Type, E.Type)) { - componentTypes = [A.self, B.self, C.self, D.self, E.self] - } - - public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (A, B, C, D, E) { - let compA: A = nexus.get(unsafeComponentFor: entityId) - let compB: B = nexus.get(unsafeComponentFor: entityId) - let compC: C = nexus.get(unsafeComponentFor: entityId) - let compD: D = nexus.get(unsafeComponentFor: entityId) - let compE: E = nexus.get(unsafeComponentFor: entityId) - return (compA, compB, compC, compD, compE) - } - - public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, A, B, C, D, E) { - let entity = nexus.get(unsafeEntity: entityId) - let compA: A = nexus.get(unsafeComponentFor: entityId) - let compB: B = nexus.get(unsafeComponentFor: entityId) - let compC: C = nexus.get(unsafeComponentFor: entityId) - let compD: D = nexus.get(unsafeComponentFor: entityId) - let compE: E = nexus.get(unsafeComponentFor: entityId) - return (entity, compA, compB, compC, compD, compE) - } - - public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> - (parent: (A, B, C, D, E), child: (A, B, C, D, E)) { - let pcA: A = nexus.get(unsafeComponentFor: parentId) - let pcB: B = nexus.get(unsafeComponentFor: parentId) - let pcC: C = nexus.get(unsafeComponentFor: parentId) - let pcD: D = nexus.get(unsafeComponentFor: parentId) - let pcE: E = nexus.get(unsafeComponentFor: parentId) - let ccA: A = nexus.get(unsafeComponentFor: childId) - let ccB: B = nexus.get(unsafeComponentFor: childId) - let ccC: C = nexus.get(unsafeComponentFor: childId) - let ccD: D = nexus.get(unsafeComponentFor: childId) - let ccE: E = nexus.get(unsafeComponentFor: childId) - return (parent: (pcA, pcB, pcC, pcD, pcE), - child: (ccA, ccB, ccC, ccD, ccE)) - } - - public static func createMember(nexus: Nexus, components: (A, B, C, D, E)) -> Entity { - nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4) - } -} - -extension Requires5: FamilyEncoding where A: Encodable, B: Encodable, C: Encodable, D: Encodable, E: Encodable { - public static func encode(components: (A, B, C, D, E), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { - try container.encode(components.0, forKey: strategy.codingKey(for: A.self)) - try container.encode(components.1, forKey: strategy.codingKey(for: B.self)) - try container.encode(components.2, forKey: strategy.codingKey(for: C.self)) - try container.encode(components.3, forKey: strategy.codingKey(for: D.self)) - try container.encode(components.4, forKey: strategy.codingKey(for: E.self)) - } -} - -extension Requires5: FamilyDecoding where A: Decodable, B: Decodable, C: Decodable, D: Decodable, E: Decodable { - public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (A, B, C, D, E) { - let compA = try container.decode(A.self, forKey: strategy.codingKey(for: A.self)) - let compB = try container.decode(B.self, forKey: strategy.codingKey(for: B.self)) - let compC = try container.decode(C.self, forKey: strategy.codingKey(for: C.self)) - let compD = try container.decode(D.self, forKey: strategy.codingKey(for: D.self)) - let compE = try container.decode(E.self, forKey: strategy.codingKey(for: E.self)) - return Components(compA, compB, compC, compD, compE) - } -} - -extension Nexus { - // swiftlint:disable function_parameter_count - public func family( - requiresAll componentA: A.Type, - _ componentB: B.Type, - _ componentC: C.Type, - _ componentD: D.Type, - _ componentE: E.Type, - excludesAll excludedComponents: Component.Type... - ) -> Family5 where A: Component, B: Component, C: Component, D: Component, E: Component { - Family5( - nexus: self, - requiresAll: (componentA, componentB, componentC, componentD, componentE), - excludesAll: excludedComponents - ) - } -} diff --git a/Sources/FirebladeECS/Stencils/Family.stencil b/Sources/FirebladeECS/Stencils/Family.stencil index 023ec9a..898b627 100644 --- a/Sources/FirebladeECS/Stencils/Family.stencil +++ b/Sources/FirebladeECS/Stencils/Family.stencil @@ -1,3 +1,108 @@ +// swiftlint:disable large_tuple // swiftlint:disable line_length // swiftlint:disable variable_name +{% for idx in 1...5 %} +{% map 1...idx into components using index %}Comp{{ index }}{% endmap %} +{% set CompParams %}{{components|join: ", "}}{% endset %} + +{% map components into compWhere using comp %}{{ comp }}: Component{% endmap %} +{% set CompsWhere %}{{compWhere|join: ", "}}{% endset %} + +{% map components into compEncodable using comp %}{{ comp }}: Encodable{% endmap %} +{% set CompsWhereEncodable %}{{compEncodable|join: ", "}}{% endset %} + +{% map components into compsDecodable using comp %}{{ comp }}: Decodable{% endmap %} +{% set CompsWhereDecodable %}{{compsDecodable|join: ", "}}{% endset %} + +{% map components into compTypes using comp %}{{ comp }}.Type{% endmap %} +{% set CompsTypes %}{{compTypes|join: ", "}}{% endset %} + +{% map components into compSelf using comp %}{{ comp }}.self{% endmap %} +{% set CompsSelf %}{{compSelf|join: ", "}}{% endset %} + +{% map components into compsLowercased using comp %}{{ comp|lowercase }}{% endmap %} +{% set CompsLowercased %}{{compsLowercased|join: ", "}}{% endset %} + +{% map components into compsTuple using comp %}components.{{ maploop.counter }}{% endmap %} +{% set CompsTuple %}{{compsTuple|join: ", "}}{% endset %} + +{% map components into compsParams using comp %}{% if not maploop.first %}_ {% endif %}{{ comp|lowercase }}: {{ comp }}.Type{% endmap %} +{% set CompsParams %}{{compsParams|join: ", "}}{% endset %} + + +// MARK: - Family {{ idx }} + +public typealias Family{{ idx }}<{{ CompParams }}> = Family> where {{ CompsWhere }} + +public struct Requires{{ idx }}<{{ CompParams }}>: FamilyRequirementsManaging where {{ CompsWhere }} { + public let componentTypes: [Component.Type] + + public init(_ components: ({{ CompsTypes }})) { + componentTypes = [{{ CompsSelf}}] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> ({{ CompParams }}) { + {% for comp in components %} + let {{ comp|lowercase }}: {{ comp }} = nexus.get(unsafeComponentFor: entityId) + {% endfor %} + return ({{ CompsLowercased }}) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, {{ CompParams }}) { + let entity: Entity = nexus.get(unsafeEntity: entityId) + {% for comp in components %} + let {{ comp|lowercase }}: {{ comp }} = nexus.get(unsafeComponentFor: entityId) + {% endfor %} + return (entity, {{ CompsLowercased }}) + } + + public static func createMember(nexus: Nexus, components: ({{ CompParams }})) -> Entity { + {% if compEncodable.count == 1 %}nexus.createEntity(with: components){% else %}nexus.createEntity(with: {{ CompsTuple }}){% endif %} + } + + public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: {{ CompParams }}, child: {{ CompParams }}) { + fatalError() + } + +} + +extension Requires{{ idx }}: FamilyEncoding where {{ CompsWhereEncodable }} { + public static func encode(components: ({{ CompParams }}), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { + {% if compEncodable.count == 1 %} + try container.encode(components, forKey: strategy.codingKey(for: {{ CompsSelf }})) + {% else %} + {% for comp in compSelf %} + try container.encode(components.{{ forloop.counter0 }}, forKey: strategy.codingKey(for: {{ comp }})) + {% endfor %} + {% endif %} + } +} + +extension Requires{{ idx }}: FamilyDecoding where {{ CompsWhereDecodable }} { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> ({{ CompParams }}) { + {% for comp in components %} + let {{ comp|lowercase }} = try container.decode({{ comp }}.self, forKey: strategy.codingKey(for: {{ comp }}.self)) + {% endfor %} + {% if compEncodable.count == 1 %} + return {{ CompsLowercased }} + {% else %} + return Components({{ CompsLowercased }}) + {% endif %} + } +} + +extension Nexus { + public func family<{{ CompParams }}>( + {% if components.count == 1 %}requires{% else %}requiresAll{%endif%} {{ CompsParams }}, + excludesAll excludedComponents: Component.Type... + ) -> Family{{ idx }}<{{ CompParams }}> where {{ CompsWhere }} { + Family{{ idx }}<{{ CompParams }}>( + nexus: self, + requiresAll: ({{ CompsLowercased }}), + excludesAll: excludedComponents + ) + } +} + +{% endfor %} \ No newline at end of file From f3d665f0be0a2c4ac8ed53f2d340070cc3c450ec Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Tue, 4 Aug 2020 16:26:52 +0200 Subject: [PATCH 04/21] Working version stencil --- Sources/FirebladeECS/Stencils/Family.stencil | 26 +++++++++----------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/Sources/FirebladeECS/Stencils/Family.stencil b/Sources/FirebladeECS/Stencils/Family.stencil index 898b627..ed3eb99 100644 --- a/Sources/FirebladeECS/Stencils/Family.stencil +++ b/Sources/FirebladeECS/Stencils/Family.stencil @@ -1,36 +1,25 @@ +// swiftlint:disable function_parameter_count // swiftlint:disable large_tuple -// swiftlint:disable line_length -// swiftlint:disable variable_name - {% for idx in 1...5 %} {% map 1...idx into components using index %}Comp{{ index }}{% endmap %} {% set CompParams %}{{components|join: ", "}}{% endset %} - {% map components into compWhere using comp %}{{ comp }}: Component{% endmap %} {% set CompsWhere %}{{compWhere|join: ", "}}{% endset %} - {% map components into compEncodable using comp %}{{ comp }}: Encodable{% endmap %} {% set CompsWhereEncodable %}{{compEncodable|join: ", "}}{% endset %} - {% map components into compsDecodable using comp %}{{ comp }}: Decodable{% endmap %} {% set CompsWhereDecodable %}{{compsDecodable|join: ", "}}{% endset %} - {% map components into compTypes using comp %}{{ comp }}.Type{% endmap %} {% set CompsTypes %}{{compTypes|join: ", "}}{% endset %} - {% map components into compSelf using comp %}{{ comp }}.self{% endmap %} {% set CompsSelf %}{{compSelf|join: ", "}}{% endset %} - {% map components into compsLowercased using comp %}{{ comp|lowercase }}{% endmap %} {% set CompsLowercased %}{{compsLowercased|join: ", "}}{% endset %} - {% map components into compsTuple using comp %}components.{{ maploop.counter }}{% endmap %} {% set CompsTuple %}{{compsTuple|join: ", "}}{% endset %} - {% map components into compsParams using comp %}{% if not maploop.first %}_ {% endif %}{{ comp|lowercase }}: {{ comp }}.Type{% endmap %} {% set CompsParams %}{{compsParams|join: ", "}}{% endset %} - // MARK: - Family {{ idx }} public typealias Family{{ idx }}<{{ CompParams }}> = Family> where {{ CompsWhere }} @@ -61,8 +50,17 @@ public struct Requires{{ idx }}<{{ CompParams }}>: FamilyRequirementsManaging wh {% if compEncodable.count == 1 %}nexus.createEntity(with: components){% else %}nexus.createEntity(with: {{ CompsTuple }}){% endif %} } - public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: {{ CompParams }}, child: {{ CompParams }}) { - fatalError() + public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: ({{ CompParams }}), child: ({{ CompParams }})) { + {% for comp in components %} + let parent{{ comp|lowercase }}: {{ comp }} = nexus.get(unsafeComponentFor: parentId) + {% endfor %} + {% for comp in components %} + let child{{ comp|lowercase }}: {{ comp }} = nexus.get(unsafeComponentFor: childId) + {% endfor %} + {% map compsLowercased into compsParent using comp %}parent{{ comp }}{% endmap %} + {% map compsLowercased into compsChild using comp %}child{{ comp }}{% endmap %} + {% set CompsParentChild %}parent: ({{compsParent|join: ", "}}), child: ({{compsChild|join: ", "}}){% endset %} + return ({{ CompsParentChild }}) } } From 5af13166f8e469a85b93bfe2c0d429109b1098b9 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Tue, 4 Aug 2020 16:27:32 +0200 Subject: [PATCH 05/21] Generate family 1...5 --- .../Generated/Family.generated.swift | 368 +++++++++++++++++- 1 file changed, 366 insertions(+), 2 deletions(-) diff --git a/Sources/FirebladeECS/Generated/Family.generated.swift b/Sources/FirebladeECS/Generated/Family.generated.swift index 5ef4cf6..d3b80ac 100644 --- a/Sources/FirebladeECS/Generated/Family.generated.swift +++ b/Sources/FirebladeECS/Generated/Family.generated.swift @@ -1,6 +1,370 @@ // Generated using Sourcery 0.18.0 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT -// swiftlint:disable line_length -// swiftlint:disable variable_name +// swiftlint:disable function_parameter_count +// swiftlint:disable large_tuple + +// MARK: - Family 1 + +public typealias Family1 = Family> where Comp1: Component + +public struct Requires1: FamilyRequirementsManaging where Comp1: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type)) { + componentTypes = [Comp1.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1) { + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + return (comp1) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1) { + let entity: Entity = nexus.get(unsafeEntity: entityId) + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + return (entity, comp1) + } + + public static func createMember(nexus: Nexus, components: (Comp1)) -> Entity { + nexus.createEntity(with: components) + } + + public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1), child: (Comp1)) { + let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId) + let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId) + return (parent: (parentcomp1), child: (childcomp1)) + } + +} + +extension Requires1: FamilyEncoding where Comp1: Encodable { + public static func encode(components: (Comp1), into container: inout KeyedEncodingContainer, using strategy: CodingStrategy) throws { + try container.encode(components, forKey: strategy.codingKey(for: Comp1.self)) + } +} + +extension Requires1: FamilyDecoding where Comp1: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1) { + let comp1 = try container.decode(Comp1.self, forKey: strategy.codingKey(for: Comp1.self)) + return comp1 + } +} + +extension Nexus { + public func family( + requires comp1: Comp1.Type, + excludesAll excludedComponents: Component.Type... + ) -> Family1 where Comp1: Component { + Family1( + nexus: self, + requiresAll: (comp1), + excludesAll: excludedComponents + ) + } +} + + +// MARK: - Family 2 + +public typealias Family2 = Family> where Comp1: Component, Comp2: Component + +public struct Requires2: FamilyRequirementsManaging where Comp1: Component, Comp2: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type)) { + componentTypes = [Comp1.self, Comp2.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2) { + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + return (comp1, comp2) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2) { + let entity: Entity = nexus.get(unsafeEntity: entityId) + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + return (entity, comp1, comp2) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2)) -> Entity { + nexus.createEntity(with: components.0, components.1) + } + + public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2), child: (Comp1, Comp2)) { + let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId) + let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId) + let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId) + let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId) + return (parent: (parentcomp1, parentcomp2), child: (childcomp1, childcomp2)) + } + +} + +extension Requires2: FamilyEncoding where Comp1: Encodable, Comp2: Encodable { + public static func encode(components: (Comp1, Comp2), 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)) + } +} + +extension Requires2: FamilyDecoding where Comp1: Decodable, Comp2: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2) { + 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)) + return Components(comp1, comp2) + } +} + +extension Nexus { + public func family( + requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, + excludesAll excludedComponents: Component.Type... + ) -> Family2 where Comp1: Component, Comp2: Component { + Family2( + nexus: self, + requiresAll: (comp1, comp2), + excludesAll: excludedComponents + ) + } +} + + +// MARK: - Family 3 + +public typealias Family3 = Family> where Comp1: Component, Comp2: Component, Comp3: Component + +public struct Requires3: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3) { + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) + return (comp1, comp2, comp3) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3) { + let entity: Entity = nexus.get(unsafeEntity: entityId) + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) + return (entity, comp1, comp2, comp3) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2) + } + + public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2, Comp3), child: (Comp1, Comp2, Comp3)) { + let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId) + let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId) + let parentcomp3: Comp3 = nexus.get(unsafeComponentFor: parentId) + let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId) + let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId) + let childcomp3: Comp3 = nexus.get(unsafeComponentFor: childId) + return (parent: (parentcomp1, parentcomp2, parentcomp3), child: (childcomp1, childcomp2, childcomp3)) + } + +} + +extension Requires3: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3), 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)) + } +} + +extension Requires3: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3) { + 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)) + return Components(comp1, comp2, comp3) + } +} + +extension Nexus { + public func family( + requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, + excludesAll excludedComponents: Component.Type... + ) -> Family3 where Comp1: Component, Comp2: Component, Comp3: Component { + Family3( + nexus: self, + requiresAll: (comp1, comp2, comp3), + excludesAll: excludedComponents + ) + } +} + + +// MARK: - Family 4 + +public typealias Family4 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component + +public struct Requires4: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4) { + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) + let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) + return (comp1, comp2, comp3, comp4) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4) { + let entity: Entity = nexus.get(unsafeEntity: entityId) + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) + let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) + return (entity, comp1, comp2, comp3, comp4) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2, components.3) + } + + public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2, Comp3, Comp4), child: (Comp1, Comp2, Comp3, Comp4)) { + let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId) + let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId) + let parentcomp3: Comp3 = nexus.get(unsafeComponentFor: parentId) + let parentcomp4: Comp4 = nexus.get(unsafeComponentFor: parentId) + let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId) + let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId) + let childcomp3: Comp3 = nexus.get(unsafeComponentFor: childId) + let childcomp4: Comp4 = nexus.get(unsafeComponentFor: childId) + return (parent: (parentcomp1, parentcomp2, parentcomp3, parentcomp4), child: (childcomp1, childcomp2, childcomp3, childcomp4)) + } + +} + +extension Requires4: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3, Comp4), 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)) + } +} + +extension Requires4: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4) { + 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)) + return Components(comp1, comp2, comp3, comp4) + } +} + +extension Nexus { + public func family( + requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, + excludesAll excludedComponents: Component.Type... + ) -> Family4 where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component { + Family4( + nexus: self, + requiresAll: (comp1, comp2, comp3, comp4), + excludesAll: excludedComponents + ) + } +} + + +// MARK: - Family 5 + +public typealias Family5 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component + +public struct Requires5: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5) { + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) + let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) + let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) + return (comp1, comp2, comp3, comp4, comp5) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5) { + let entity: Entity = nexus.get(unsafeEntity: entityId) + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) + let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) + let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) + return (entity, comp1, comp2, comp3, comp4, comp5) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4) + } + + public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2, Comp3, Comp4, Comp5), child: (Comp1, Comp2, Comp3, Comp4, Comp5)) { + let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId) + let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId) + let parentcomp3: Comp3 = nexus.get(unsafeComponentFor: parentId) + let parentcomp4: Comp4 = nexus.get(unsafeComponentFor: parentId) + let parentcomp5: Comp5 = nexus.get(unsafeComponentFor: parentId) + let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId) + let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId) + let childcomp3: Comp3 = nexus.get(unsafeComponentFor: childId) + let childcomp4: Comp4 = nexus.get(unsafeComponentFor: childId) + let childcomp5: Comp5 = nexus.get(unsafeComponentFor: childId) + return (parent: (parentcomp1, parentcomp2, parentcomp3, parentcomp4, parentcomp5), child: (childcomp1, childcomp2, childcomp3, childcomp4, childcomp5)) + } + +} + +extension Requires5: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5), 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)) + } +} + +extension Requires5: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5) { + 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)) + return Components(comp1, comp2, comp3, comp4, comp5) + } +} + +extension Nexus { + public func family( + requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type, + excludesAll excludedComponents: Component.Type... + ) -> Family5 where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component { + Family5( + nexus: self, + requiresAll: (comp1, comp2, comp3, comp4, comp5), + excludesAll: excludedComponents + ) + } +} From 8490fe481c76a00e41129db61bf79baa531c7a97 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Tue, 4 Aug 2020 16:29:27 +0200 Subject: [PATCH 06/21] Lint --- Sources/FirebladeECS/Generated/Family.generated.swift | 10 ---------- Sources/FirebladeECS/Stencils/Family.stencil | 1 - 2 files changed, 11 deletions(-) diff --git a/Sources/FirebladeECS/Generated/Family.generated.swift b/Sources/FirebladeECS/Generated/Family.generated.swift index d3b80ac..550674c 100644 --- a/Sources/FirebladeECS/Generated/Family.generated.swift +++ b/Sources/FirebladeECS/Generated/Family.generated.swift @@ -35,7 +35,6 @@ public struct Requires1: FamilyRequirementsManaging where Comp1: Componen let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId) return (parent: (parentcomp1), child: (childcomp1)) } - } extension Requires1: FamilyEncoding where Comp1: Encodable { @@ -64,7 +63,6 @@ extension Nexus { } } - // MARK: - Family 2 public typealias Family2 = Family> where Comp1: Component, Comp2: Component @@ -100,7 +98,6 @@ public struct Requires2: FamilyRequirementsManaging where Comp1: C let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId) return (parent: (parentcomp1, parentcomp2), child: (childcomp1, childcomp2)) } - } extension Requires2: FamilyEncoding where Comp1: Encodable, Comp2: Encodable { @@ -131,7 +128,6 @@ extension Nexus { } } - // MARK: - Family 3 public typealias Family3 = Family> where Comp1: Component, Comp2: Component, Comp3: Component @@ -171,7 +167,6 @@ public struct Requires3: FamilyRequirementsManaging where C let childcomp3: Comp3 = nexus.get(unsafeComponentFor: childId) return (parent: (parentcomp1, parentcomp2, parentcomp3), child: (childcomp1, childcomp2, childcomp3)) } - } extension Requires3: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable { @@ -204,7 +199,6 @@ extension Nexus { } } - // MARK: - Family 4 public typealias Family4 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component @@ -248,7 +242,6 @@ public struct Requires4: FamilyRequirementsManaging let childcomp4: Comp4 = nexus.get(unsafeComponentFor: childId) return (parent: (parentcomp1, parentcomp2, parentcomp3, parentcomp4), child: (childcomp1, childcomp2, childcomp3, childcomp4)) } - } extension Requires4: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable { @@ -283,7 +276,6 @@ extension Nexus { } } - // MARK: - Family 5 public typealias Family5 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component @@ -331,7 +323,6 @@ public struct Requires5: FamilyRequirementsMa let childcomp5: Comp5 = nexus.get(unsafeComponentFor: childId) return (parent: (parentcomp1, parentcomp2, parentcomp3, parentcomp4, parentcomp5), child: (childcomp1, childcomp2, childcomp3, childcomp4, childcomp5)) } - } extension Requires5: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable { @@ -367,4 +358,3 @@ extension Nexus { ) } } - diff --git a/Sources/FirebladeECS/Stencils/Family.stencil b/Sources/FirebladeECS/Stencils/Family.stencil index ed3eb99..e2f7dd6 100644 --- a/Sources/FirebladeECS/Stencils/Family.stencil +++ b/Sources/FirebladeECS/Stencils/Family.stencil @@ -102,5 +102,4 @@ extension Nexus { ) } } - {% endfor %} \ No newline at end of file From c20444d0690e8081b7c32dbb6db43825d008f417 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Tue, 4 Aug 2020 16:32:21 +0200 Subject: [PATCH 07/21] Stencil --- Sources/FirebladeECS/Stencils/Family.stencil | 1 - 1 file changed, 1 deletion(-) diff --git a/Sources/FirebladeECS/Stencils/Family.stencil b/Sources/FirebladeECS/Stencils/Family.stencil index e2f7dd6..fef5da8 100644 --- a/Sources/FirebladeECS/Stencils/Family.stencil +++ b/Sources/FirebladeECS/Stencils/Family.stencil @@ -62,7 +62,6 @@ public struct Requires{{ idx }}<{{ CompParams }}>: FamilyRequirementsManaging wh {% set CompsParentChild %}parent: ({{compsParent|join: ", "}}), child: ({{compsChild|join: ", "}}){% endset %} return ({{ CompsParentChild }}) } - } extension Requires{{ idx }}: FamilyEncoding where {{ CompsWhereEncodable }} { From 2d56682568e975c0195c917a3b50c4e4f1551587 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Tue, 4 Aug 2020 17:15:13 +0200 Subject: [PATCH 08/21] Add documentation to family creator function --- Sources/FirebladeECS/Stencils/Family.stencil | 29 ++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Sources/FirebladeECS/Stencils/Family.stencil b/Sources/FirebladeECS/Stencils/Family.stencil index fef5da8..5f033bd 100644 --- a/Sources/FirebladeECS/Stencils/Family.stencil +++ b/Sources/FirebladeECS/Stencils/Family.stencil @@ -90,6 +90,35 @@ extension Requires{{ idx }}: FamilyDecoding where {{ CompsWhereDecodable }} { } extension Nexus { + /// Create a family of entities (aka members) having {{ components.count }} required components. + /// + /// A family is a collection of entities with uniform components per entity. + /// Entities that will be part of this family will have at least the {{ components.count }} required components, + /// but may have more components assigned. + /// + /// Families are just views on data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families of the same requirements provide a view on the same collection of entities. + /// Each family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **Usage example:** + /// ```swift + /// let family = nexus.family(requiresAll: {{ CompsSelf }}) + /// // iterate each entity's components + /// family.forEach { ({{ CompsLowercased }}) in + /// ... + /// } + /// ``` + /// **Note:** + /// - Component types must be unique per family + /// - Component type order is arbitrary + /// + /// - Parameters: + {% for comp in compsLowercased %} + /// - {{ comp }}: Component type {{ forloop.counter }} required by members of this family. + {% endfor %} + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having {{ components.count }} required components each. public func family<{{ CompParams }}>( {% if components.count == 1 %}requires{% else %}requiresAll{%endif%} {{ CompsParams }}, excludesAll excludedComponents: Component.Type... From 1bf4ea9eff285e50403ee01b657d13d891aeb560 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Tue, 4 Aug 2020 17:15:40 +0200 Subject: [PATCH 09/21] Generate --- .../Generated/Family.generated.swift | 145 ++++++++++++++++++ 1 file changed, 145 insertions(+) diff --git a/Sources/FirebladeECS/Generated/Family.generated.swift b/Sources/FirebladeECS/Generated/Family.generated.swift index 550674c..997aa7c 100644 --- a/Sources/FirebladeECS/Generated/Family.generated.swift +++ b/Sources/FirebladeECS/Generated/Family.generated.swift @@ -51,6 +51,33 @@ extension Requires1: FamilyDecoding where Comp1: Decodable { } extension Nexus { + /// Create a family of entities (aka members) having 1 required components. + /// + /// A family is a collection of entities with uniform components per entity. + /// Entities that will be part of this family will have at least the 1 required components, + /// but may have more components assigned. + /// + /// Families are just views on data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families of the same requirements provide a view on the same collection of entities. + /// Each family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **Usage example:** + /// ```swift + /// let family = nexus.family(requiresAll: Comp1.self) + /// // iterate each entity's components + /// family.forEach { (comp1) in + /// ... + /// } + /// ``` + /// **Note:** + /// - Component types must be unique per family + /// - Component type order is arbitrary + /// + /// - Parameters: + /// - comp1: Component type 1 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 1 required components each. public func family( requires comp1: Comp1.Type, excludesAll excludedComponents: Component.Type... @@ -116,6 +143,34 @@ extension Requires2: FamilyDecoding where Comp1: Decodable, Comp2: Decodable { } extension Nexus { + /// Create a family of entities (aka members) having 2 required components. + /// + /// A family is a collection of entities with uniform components per entity. + /// Entities that will be part of this family will have at least the 2 required components, + /// but may have more components assigned. + /// + /// Families are just views on data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families of the same requirements provide a view on the same collection of entities. + /// Each family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **Usage example:** + /// ```swift + /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2) in + /// ... + /// } + /// ``` + /// **Note:** + /// - 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. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 2 required components each. public func family( requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, excludesAll excludedComponents: Component.Type... @@ -187,6 +242,35 @@ extension Requires3: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Co } extension Nexus { + /// Create a family of entities (aka members) having 3 required components. + /// + /// A family is a collection of entities with uniform components per entity. + /// Entities that will be part of this family will have at least the 3 required components, + /// but may have more components assigned. + /// + /// Families are just views on data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families of the same requirements provide a view on the same collection of entities. + /// Each family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **Usage example:** + /// ```swift + /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3) in + /// ... + /// } + /// ``` + /// **Note:** + /// - 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. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 3 required components each. public func family( requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, excludesAll excludedComponents: Component.Type... @@ -264,6 +348,36 @@ extension Requires4: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Co } extension Nexus { + /// Create a family of entities (aka members) having 4 required components. + /// + /// A family is a collection of entities with uniform components per entity. + /// Entities that will be part of this family will have at least the 4 required components, + /// but may have more components assigned. + /// + /// Families are just views on data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families of the same requirements provide a view on the same collection of entities. + /// Each family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **Usage example:** + /// ```swift + /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3, comp4) in + /// ... + /// } + /// ``` + /// **Note:** + /// - 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. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 4 required components each. public func family( requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, excludesAll excludedComponents: Component.Type... @@ -347,6 +461,37 @@ extension Requires5: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Co } extension Nexus { + /// Create a family of entities (aka members) having 5 required components. + /// + /// A family is a collection of entities with uniform components per entity. + /// Entities that will be part of this family will have at least the 5 required components, + /// but may have more components assigned. + /// + /// Families are just views on data, creating them is cheap. + /// Use them to iterate efficiently over entities with the same components assigned. + /// Families of the same requirements provide a view on the same collection of entities. + /// Each family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// + /// **Usage example:** + /// ```swift + /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3, comp4, comp5) in + /// ... + /// } + /// ``` + /// **Note:** + /// - 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. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 5 required components each. public func family( requiresAll comp1: Comp1.Type, _ comp2: Comp2.Type, _ comp3: Comp3.Type, _ comp4: Comp4.Type, _ comp5: Comp5.Type, excludesAll excludedComponents: Component.Type... From cae23ea2191366ea35572cd7090844cf64ecb480 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Tue, 4 Aug 2020 17:17:17 +0200 Subject: [PATCH 10/21] Lint --- Sources/FirebladeECS/Generated/Family.generated.swift | 2 ++ Sources/FirebladeECS/Stencils/Family.stencil | 2 ++ 2 files changed, 4 insertions(+) diff --git a/Sources/FirebladeECS/Generated/Family.generated.swift b/Sources/FirebladeECS/Generated/Family.generated.swift index 997aa7c..5150709 100644 --- a/Sources/FirebladeECS/Generated/Family.generated.swift +++ b/Sources/FirebladeECS/Generated/Family.generated.swift @@ -1,8 +1,10 @@ // Generated using Sourcery 0.18.0 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT +// swiftlint:disable file_length // swiftlint:disable function_parameter_count // swiftlint:disable large_tuple +// swiftlint:disable multiline_parameters // MARK: - Family 1 diff --git a/Sources/FirebladeECS/Stencils/Family.stencil b/Sources/FirebladeECS/Stencils/Family.stencil index 5f033bd..853044c 100644 --- a/Sources/FirebladeECS/Stencils/Family.stencil +++ b/Sources/FirebladeECS/Stencils/Family.stencil @@ -1,5 +1,7 @@ +// swiftlint:disable file_length // swiftlint:disable function_parameter_count // swiftlint:disable large_tuple +// swiftlint:disable multiline_parameters {% for idx in 1...5 %} {% map 1...idx into components using index %}Comp{{ index }}{% endmap %} {% set CompParams %}{{components|join: ", "}}{% endset %} From 35f733bd967e2c536e72aaad5dc8e2eeb4b8fc3f Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Tue, 4 Aug 2020 17:22:18 +0200 Subject: [PATCH 11/21] Update documentation --- .../Generated/Family.generated.swift | 62 +++++++++---------- Sources/FirebladeECS/Stencils/Family.stencil | 14 ++--- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/Sources/FirebladeECS/Generated/Family.generated.swift b/Sources/FirebladeECS/Generated/Family.generated.swift index 5150709..a57c990 100644 --- a/Sources/FirebladeECS/Generated/Family.generated.swift +++ b/Sources/FirebladeECS/Generated/Family.generated.swift @@ -55,18 +55,18 @@ extension Requires1: FamilyDecoding where Comp1: Decodable { extension Nexus { /// Create a family of entities (aka members) having 1 required components. /// - /// A family is a collection of entities with uniform components per entity. - /// Entities that will be part of this family will have at least the 1 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 1 required components, /// but may have more components assigned. /// - /// Families are just views on data, creating them is cheap. + /// 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 of the same requirements provide a view on the same collection of entities. - /// Each family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// 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. /// - /// **Usage example:** + /// **General usage:** /// ```swift - /// let family = nexus.family(requiresAll: Comp1.self) + /// let family = nexus.family(requires: Comp1.self) /// // iterate each entity's components /// family.forEach { (comp1) in /// ... @@ -147,16 +147,16 @@ extension Requires2: FamilyDecoding where Comp1: Decodable, Comp2: Decodable { extension Nexus { /// Create a family of entities (aka members) having 2 required components. /// - /// A family is a collection of entities with uniform components per entity. - /// Entities that will be part of this family will have at least the 2 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 2 required components, /// but may have more components assigned. /// - /// Families are just views on data, creating them is cheap. + /// 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 of the same requirements provide a view on the same collection of entities. - /// Each family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// 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. /// - /// **Usage example:** + /// **General usage:** /// ```swift /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self) /// // iterate each entity's components @@ -246,16 +246,16 @@ extension Requires3: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Co extension Nexus { /// Create a family of entities (aka members) having 3 required components. /// - /// A family is a collection of entities with uniform components per entity. - /// Entities that will be part of this family will have at least the 3 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 3 required components, /// but may have more components assigned. /// - /// Families are just views on data, creating them is cheap. + /// 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 of the same requirements provide a view on the same collection of entities. - /// Each family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// 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. /// - /// **Usage example:** + /// **General usage:** /// ```swift /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self) /// // iterate each entity's components @@ -352,16 +352,16 @@ extension Requires4: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Co extension Nexus { /// Create a family of entities (aka members) having 4 required components. /// - /// A family is a collection of entities with uniform components per entity. - /// Entities that will be part of this family will have at least the 4 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 4 required components, /// but may have more components assigned. /// - /// Families are just views on data, creating them is cheap. + /// 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 of the same requirements provide a view on the same collection of entities. - /// Each family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// 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. /// - /// **Usage example:** + /// **General usage:** /// ```swift /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self) /// // iterate each entity's components @@ -465,16 +465,16 @@ extension Requires5: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Co extension Nexus { /// Create a family of entities (aka members) having 5 required components. /// - /// A family is a collection of entities with uniform components per entity. - /// Entities that will be part of this family will have at least the 5 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 5 required components, /// but may have more components assigned. /// - /// Families are just views on data, creating them is cheap. + /// 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 of the same requirements provide a view on the same collection of entities. - /// Each family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// 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. /// - /// **Usage example:** + /// **General usage:** /// ```swift /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self) /// // iterate each entity's components diff --git a/Sources/FirebladeECS/Stencils/Family.stencil b/Sources/FirebladeECS/Stencils/Family.stencil index 853044c..2894c37 100644 --- a/Sources/FirebladeECS/Stencils/Family.stencil +++ b/Sources/FirebladeECS/Stencils/Family.stencil @@ -94,18 +94,18 @@ extension Requires{{ idx }}: FamilyDecoding where {{ CompsWhereDecodable }} { extension Nexus { /// Create a family of entities (aka members) having {{ components.count }} required components. /// - /// A family is a collection of entities with uniform components per entity. - /// Entities that will be part of this family will have at least the {{ components.count }} 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 {{ components.count }} required components, /// but may have more components assigned. /// - /// Families are just views on data, creating them is cheap. + /// 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 of the same requirements provide a view on the same collection of entities. - /// Each family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. + /// 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. /// - /// **Usage example:** + /// **General usage:** /// ```swift - /// let family = nexus.family(requiresAll: {{ CompsSelf }}) + /// let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) /// // iterate each entity's components /// family.forEach { ({{ CompsLowercased }}) in /// ... From 8229254e99420c7a5483c14111f414e345d0a253 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Tue, 4 Aug 2020 17:26:17 +0200 Subject: [PATCH 12/21] Updates --- Makefile | 2 +- .../Generated/Family.generated.swift | 20 +++++++++---------- Sources/FirebladeECS/Stencils/Family.stencil | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Makefile b/Makefile index 8077b48..5008046 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ lintErrorOnly: @swiftlint lint --quiet | grep error # Git -precommit: lint genLinuxTests +precommit: generateCode lint genLinuxTests submodule: git submodule init diff --git a/Sources/FirebladeECS/Generated/Family.generated.swift b/Sources/FirebladeECS/Generated/Family.generated.swift index a57c990..bc077a2 100644 --- a/Sources/FirebladeECS/Generated/Family.generated.swift +++ b/Sources/FirebladeECS/Generated/Family.generated.swift @@ -64,7 +64,7 @@ extension Nexus { /// 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:** + /// **General usage** /// ```swift /// let family = nexus.family(requires: Comp1.self) /// // iterate each entity's components @@ -72,7 +72,7 @@ extension Nexus { /// ... /// } /// ``` - /// **Note:** + /// **Caveats** /// - Component types must be unique per family /// - Component type order is arbitrary /// @@ -156,7 +156,7 @@ extension Nexus { /// 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:** + /// **General usage** /// ```swift /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self) /// // iterate each entity's components @@ -164,7 +164,7 @@ extension Nexus { /// ... /// } /// ``` - /// **Note:** + /// **Caveats** /// - Component types must be unique per family /// - Component type order is arbitrary /// @@ -255,7 +255,7 @@ extension Nexus { /// 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:** + /// **General usage** /// ```swift /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self) /// // iterate each entity's components @@ -263,7 +263,7 @@ extension Nexus { /// ... /// } /// ``` - /// **Note:** + /// **Caveats** /// - Component types must be unique per family /// - Component type order is arbitrary /// @@ -361,7 +361,7 @@ extension Nexus { /// 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:** + /// **General usage** /// ```swift /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self) /// // iterate each entity's components @@ -369,7 +369,7 @@ extension Nexus { /// ... /// } /// ``` - /// **Note:** + /// **Caveats** /// - Component types must be unique per family /// - Component type order is arbitrary /// @@ -474,7 +474,7 @@ extension Nexus { /// 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:** + /// **General usage** /// ```swift /// let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self) /// // iterate each entity's components @@ -482,7 +482,7 @@ extension Nexus { /// ... /// } /// ``` - /// **Note:** + /// **Caveats** /// - Component types must be unique per family /// - Component type order is arbitrary /// diff --git a/Sources/FirebladeECS/Stencils/Family.stencil b/Sources/FirebladeECS/Stencils/Family.stencil index 2894c37..bfbc17e 100644 --- a/Sources/FirebladeECS/Stencils/Family.stencil +++ b/Sources/FirebladeECS/Stencils/Family.stencil @@ -103,7 +103,7 @@ extension Nexus { /// 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:** + /// **General usage** /// ```swift /// let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) /// // iterate each entity's components @@ -111,7 +111,7 @@ extension Nexus { /// ... /// } /// ``` - /// **Note:** + /// **Caveats** /// - Component types must be unique per family /// - Component type order is arbitrary /// From d48249dbfaaeb3f67e54b65613da8555755a8925 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Wed, 5 Aug 2020 09:15:55 +0200 Subject: [PATCH 13/21] Generate 8 families --- .../Generated/Family.generated.swift | 384 ++++++++++++++++++ Sources/FirebladeECS/Stencils/Family.stencil | 14 +- 2 files changed, 391 insertions(+), 7 deletions(-) diff --git a/Sources/FirebladeECS/Generated/Family.generated.swift b/Sources/FirebladeECS/Generated/Family.generated.swift index bc077a2..5e4f716 100644 --- a/Sources/FirebladeECS/Generated/Family.generated.swift +++ b/Sources/FirebladeECS/Generated/Family.generated.swift @@ -505,3 +505,387 @@ extension Nexus { ) } } + +// MARK: - Family 6 + +public typealias Family6 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component + +public struct Requires6: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type, Comp6.Type)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6) { + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) + let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) + let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) + let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId) + return (comp1, comp2, comp3, comp4, comp5, comp6) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6) { + let entity: Entity = nexus.get(unsafeEntity: entityId) + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) + let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) + let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) + let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId) + return (entity, comp1, comp2, comp3, comp4, comp5, comp6) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5) + } + + public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6), child: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6)) { + let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId) + let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId) + let parentcomp3: Comp3 = nexus.get(unsafeComponentFor: parentId) + let parentcomp4: Comp4 = nexus.get(unsafeComponentFor: parentId) + let parentcomp5: Comp5 = nexus.get(unsafeComponentFor: parentId) + let parentcomp6: Comp6 = nexus.get(unsafeComponentFor: parentId) + let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId) + let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId) + let childcomp3: Comp3 = nexus.get(unsafeComponentFor: childId) + let childcomp4: Comp4 = nexus.get(unsafeComponentFor: childId) + let childcomp5: Comp5 = nexus.get(unsafeComponentFor: childId) + let childcomp6: Comp6 = nexus.get(unsafeComponentFor: childId) + return (parent: (parentcomp1, parentcomp2, parentcomp3, parentcomp4, parentcomp5, parentcomp6), child: (childcomp1, childcomp2, childcomp3, childcomp4, childcomp5, childcomp6)) + } +} + +extension Requires6: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6), 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)) + } +} + +extension Requires6: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6) { + 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)) + return Components(comp1, comp2, comp3, comp4, comp5, comp6) + } +} + +extension Nexus { + /// Create a family of entities (aka members) having 6 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 6 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) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6) 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. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 6 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, + excludesAll excludedComponents: Component.Type... + ) -> Family6 where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component { + Family6( + nexus: self, + requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6), + excludesAll: excludedComponents + ) + } +} + +// MARK: - Family 7 + +public typealias Family7 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component + +public struct Requires7: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component { + public let componentTypes: [Component.Type] + + public init(_ components: (Comp1.Type, Comp2.Type, Comp3.Type, Comp4.Type, Comp5.Type, Comp6.Type, Comp7.Type)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7) { + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) + let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) + let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) + let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId) + let comp7: Comp7 = nexus.get(unsafeComponentFor: entityId) + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7) { + let entity: Entity = nexus.get(unsafeEntity: entityId) + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) + let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) + let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) + let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId) + let comp7: Comp7 = nexus.get(unsafeComponentFor: entityId) + return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5, components.6) + } + + public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7), child: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7)) { + let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId) + let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId) + let parentcomp3: Comp3 = nexus.get(unsafeComponentFor: parentId) + let parentcomp4: Comp4 = nexus.get(unsafeComponentFor: parentId) + let parentcomp5: Comp5 = nexus.get(unsafeComponentFor: parentId) + let parentcomp6: Comp6 = nexus.get(unsafeComponentFor: parentId) + let parentcomp7: Comp7 = nexus.get(unsafeComponentFor: parentId) + let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId) + let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId) + let childcomp3: Comp3 = nexus.get(unsafeComponentFor: childId) + let childcomp4: Comp4 = nexus.get(unsafeComponentFor: childId) + let childcomp5: Comp5 = nexus.get(unsafeComponentFor: childId) + let childcomp6: Comp6 = nexus.get(unsafeComponentFor: childId) + let childcomp7: Comp7 = nexus.get(unsafeComponentFor: childId) + return (parent: (parentcomp1, parentcomp2, parentcomp3, parentcomp4, parentcomp5, parentcomp6, parentcomp7), child: (childcomp1, childcomp2, childcomp3, childcomp4, childcomp5, childcomp6, childcomp7)) + } +} + +extension Requires7: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable, Comp7: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7), 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)) + } +} + +extension Requires7: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable, Comp7: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7) { + 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)) + return Components(comp1, comp2, comp3, comp4, comp5, comp6, comp7) + } +} + +extension Nexus { + /// Create a family of entities (aka members) having 7 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 7 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) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7) 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. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 7 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, + excludesAll excludedComponents: Component.Type... + ) -> Family7 where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component { + Family7( + nexus: self, + requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6, comp7), + excludesAll: excludedComponents + ) + } +} + +// MARK: - Family 8 + +public typealias Family8 = Family> where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component + +public struct Requires8: FamilyRequirementsManaging where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: 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)) { + componentTypes = [Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self] + } + + public static func components(nexus: Nexus, entityId: EntityIdentifier) -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8) { + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) + let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) + let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) + let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId) + let comp7: Comp7 = nexus.get(unsafeComponentFor: entityId) + let comp8: Comp8 = nexus.get(unsafeComponentFor: entityId) + return (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8) + } + + public static func entityAndComponents(nexus: Nexus, entityId: EntityIdentifier) -> (Entity, Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8) { + let entity: Entity = nexus.get(unsafeEntity: entityId) + let comp1: Comp1 = nexus.get(unsafeComponentFor: entityId) + let comp2: Comp2 = nexus.get(unsafeComponentFor: entityId) + let comp3: Comp3 = nexus.get(unsafeComponentFor: entityId) + let comp4: Comp4 = nexus.get(unsafeComponentFor: entityId) + let comp5: Comp5 = nexus.get(unsafeComponentFor: entityId) + let comp6: Comp6 = nexus.get(unsafeComponentFor: entityId) + let comp7: Comp7 = nexus.get(unsafeComponentFor: entityId) + let comp8: Comp8 = nexus.get(unsafeComponentFor: entityId) + return (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8) + } + + public static func createMember(nexus: Nexus, components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8)) -> Entity { + nexus.createEntity(with: components.0, components.1, components.2, components.3, components.4, components.5, components.6, components.7) + } + + public static func relativesDescending(nexus: Nexus, parentId: EntityIdentifier, childId: EntityIdentifier) -> (parent: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8), child: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8)) { + let parentcomp1: Comp1 = nexus.get(unsafeComponentFor: parentId) + let parentcomp2: Comp2 = nexus.get(unsafeComponentFor: parentId) + let parentcomp3: Comp3 = nexus.get(unsafeComponentFor: parentId) + let parentcomp4: Comp4 = nexus.get(unsafeComponentFor: parentId) + let parentcomp5: Comp5 = nexus.get(unsafeComponentFor: parentId) + let parentcomp6: Comp6 = nexus.get(unsafeComponentFor: parentId) + let parentcomp7: Comp7 = nexus.get(unsafeComponentFor: parentId) + let parentcomp8: Comp8 = nexus.get(unsafeComponentFor: parentId) + let childcomp1: Comp1 = nexus.get(unsafeComponentFor: childId) + let childcomp2: Comp2 = nexus.get(unsafeComponentFor: childId) + let childcomp3: Comp3 = nexus.get(unsafeComponentFor: childId) + let childcomp4: Comp4 = nexus.get(unsafeComponentFor: childId) + let childcomp5: Comp5 = nexus.get(unsafeComponentFor: childId) + let childcomp6: Comp6 = nexus.get(unsafeComponentFor: childId) + let childcomp7: Comp7 = nexus.get(unsafeComponentFor: childId) + let childcomp8: Comp8 = nexus.get(unsafeComponentFor: childId) + return (parent: (parentcomp1, parentcomp2, parentcomp3, parentcomp4, parentcomp5, parentcomp6, parentcomp7, parentcomp8), child: (childcomp1, childcomp2, childcomp3, childcomp4, childcomp5, childcomp6, childcomp7, childcomp8)) + } +} + +extension Requires8: FamilyEncoding where Comp1: Encodable, Comp2: Encodable, Comp3: Encodable, Comp4: Encodable, Comp5: Encodable, Comp6: Encodable, Comp7: Encodable, Comp8: Encodable { + public static func encode(components: (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8), 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)) + } +} + +extension Requires8: FamilyDecoding where Comp1: Decodable, Comp2: Decodable, Comp3: Decodable, Comp4: Decodable, Comp5: Decodable, Comp6: Decodable, Comp7: Decodable, Comp8: Decodable { + public static func decode(componentsIn container: KeyedDecodingContainer, using strategy: CodingStrategy) throws -> (Comp1, Comp2, Comp3, Comp4, Comp5, Comp6, Comp7, Comp8) { + 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)) + return Components(comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8) + } +} + +extension Nexus { + /// Create a family of entities (aka members) having 8 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 8 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) + /// // iterate each entity's components + /// family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8) 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. + /// - excludedComponents: All component types that must not be assigned to an entity in this family. + /// - Returns: The family of entities having 8 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, + excludesAll excludedComponents: Component.Type... + ) -> Family8 where Comp1: Component, Comp2: Component, Comp3: Component, Comp4: Component, Comp5: Component, Comp6: Component, Comp7: Component, Comp8: Component { + Family8( + nexus: self, + requiresAll: (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8), + excludesAll: excludedComponents + ) + } +} diff --git a/Sources/FirebladeECS/Stencils/Family.stencil b/Sources/FirebladeECS/Stencils/Family.stencil index bfbc17e..b7110d3 100644 --- a/Sources/FirebladeECS/Stencils/Family.stencil +++ b/Sources/FirebladeECS/Stencils/Family.stencil @@ -2,7 +2,7 @@ // swiftlint:disable function_parameter_count // swiftlint:disable large_tuple // swiftlint:disable multiline_parameters -{% for idx in 1...5 %} +{% for idx in 1...8 %} {% map 1...idx into components using index %}Comp{{ index }}{% endmap %} {% set CompParams %}{{components|join: ", "}}{% endset %} {% map components into compWhere using comp %}{{ comp }}: Component{% endmap %} @@ -94,21 +94,21 @@ extension Requires{{ idx }}: FamilyDecoding where {{ CompsWhereDecodable }} { extension Nexus { /// Create a family of entities (aka members) having {{ components.count }} 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 {{ components.count }} 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 {{ components.count }} 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. + /// A family conforms to the `LazySequenceProtocol` and therefore can be accessed like any other (lazy) sequence. /// /// **General usage** /// ```swift /// let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) /// // iterate each entity's components - /// family.forEach { ({{ CompsLowercased }}) in - /// ... + /// family.forEach { ({{ CompsLowercased }}) in + /// ... /// } /// ``` /// **Caveats** @@ -132,4 +132,4 @@ extension Nexus { ) } } -{% endfor %} \ No newline at end of file +{% endfor %} From dc6db4ed2619e974414f5ed29efae3117a8262b8 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Wed, 5 Aug 2020 10:36:13 +0200 Subject: [PATCH 14/21] Add disable line length exception --- Sources/FirebladeECS/Generated/Family.generated.swift | 1 + Sources/FirebladeECS/Stencils/Family.stencil | 1 + 2 files changed, 2 insertions(+) diff --git a/Sources/FirebladeECS/Generated/Family.generated.swift b/Sources/FirebladeECS/Generated/Family.generated.swift index 5e4f716..456eea6 100644 --- a/Sources/FirebladeECS/Generated/Family.generated.swift +++ b/Sources/FirebladeECS/Generated/Family.generated.swift @@ -4,6 +4,7 @@ // swiftlint:disable file_length // swiftlint:disable function_parameter_count // swiftlint:disable large_tuple +// swiftlint:disable line_length // swiftlint:disable multiline_parameters // MARK: - Family 1 diff --git a/Sources/FirebladeECS/Stencils/Family.stencil b/Sources/FirebladeECS/Stencils/Family.stencil index b7110d3..865780c 100644 --- a/Sources/FirebladeECS/Stencils/Family.stencil +++ b/Sources/FirebladeECS/Stencils/Family.stencil @@ -1,6 +1,7 @@ // swiftlint:disable file_length // swiftlint:disable function_parameter_count // swiftlint:disable large_tuple +// swiftlint:disable line_length // swiftlint:disable multiline_parameters {% for idx in 1...8 %} {% map 1...idx into components using index %}Comp{{ index }}{% endmap %} From 0b273542fc3ae9e5278a1f78ab2e0dda9571378d Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Wed, 5 Aug 2020 16:10:20 +0200 Subject: [PATCH 15/21] Refine family stencil --- Makefile | 2 +- Sources/FirebladeECS/Stencils/Family.stencil | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 5008046..d95052b 100644 --- a/Makefile +++ b/Makefile @@ -62,4 +62,4 @@ setupEnvironment: brew install sourcery generateCode: - sourcery --verbose \ No newline at end of file + sourcery --config ./.sourcery.yml --verbose \ No newline at end of file diff --git a/Sources/FirebladeECS/Stencils/Family.stencil b/Sources/FirebladeECS/Stencils/Family.stencil index 865780c..e01b327 100644 --- a/Sources/FirebladeECS/Stencils/Family.stencil +++ b/Sources/FirebladeECS/Stencils/Family.stencil @@ -20,8 +20,10 @@ {% set CompsLowercased %}{{compsLowercased|join: ", "}}{% endset %} {% map components into compsTuple using comp %}components.{{ maploop.counter }}{% endmap %} {% set CompsTuple %}{{compsTuple|join: ", "}}{% endset %} -{% map components into compsParams using comp %}{% if not maploop.first %}_ {% endif %}{{ comp|lowercase }}: {{ comp }}.Type{% endmap %} -{% set CompsParams %}{{compsParams|join: ", "}}{% endset %} +{% map components into compsTypeParams using comp %}{% if not maploop.first %}_ {% endif %}{{ comp|lowercase }}: {{ comp }}.Type{% endmap %} +{% set CompsTypeParams %}{{compsTypeParams|join: ", "}}{% endset %} +{% map components into compsNamedParams using comp %}{% if not maploop.first %}_ {% endif %}{{ comp|lowercase }}: {{ comp }}{% endmap %} +{% set CompsNamedParams %}{{compsNamedParams|join: ", "}}{% endset %} // MARK: - Family {{ idx }} @@ -123,7 +125,7 @@ extension Nexus { /// - excludedComponents: All component types that must not be assigned to an entity in this family. /// - Returns: The family of entities having {{ components.count }} required components each. public func family<{{ CompParams }}>( - {% if components.count == 1 %}requires{% else %}requiresAll{%endif%} {{ CompsParams }}, + {% if components.count == 1 %}requires{% else %}requiresAll{%endif%} {{ CompsTypeParams }}, excludesAll excludedComponents: Component.Type... ) -> Family{{ idx }}<{{ CompParams }}> where {{ CompsWhere }} { Family{{ idx }}<{{ CompParams }}>( From 7db68e0d80ed550e2a9e4b7311d0700a13dee5e4 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Wed, 5 Aug 2020 16:11:10 +0200 Subject: [PATCH 16/21] Add family tests stencil --- .sourceryTests.yml | 6 + Makefile | 6 +- Tests/FirebladeECSTests/Generated/.gitkeep | 0 .../Stencils/FamilyTests.stencil | 156 ++++++++++++++++++ 4 files changed, 166 insertions(+), 2 deletions(-) create mode 100644 .sourceryTests.yml create mode 100644 Tests/FirebladeECSTests/Generated/.gitkeep create mode 100644 Tests/FirebladeECSTests/Stencils/FamilyTests.stencil diff --git a/.sourceryTests.yml b/.sourceryTests.yml new file mode 100644 index 0000000..80db363 --- /dev/null +++ b/.sourceryTests.yml @@ -0,0 +1,6 @@ +sources: # you can provide either single path or several paths using `-` + - Sources +templates: # as well as for templates + - Tests/FirebladeECSTests/Stencils +output: # note that there is no `-` here as only single output path is supported + Tests/FirebladeECSTests/Generated diff --git a/Makefile b/Makefile index d95052b..f30b7b3 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ lintErrorOnly: @swiftlint lint --quiet | grep error # Git -precommit: generateCode lint genLinuxTests +precommit: generateCode generateTestsCode lint genLinuxTests submodule: git submodule init @@ -62,4 +62,6 @@ setupEnvironment: brew install sourcery generateCode: - sourcery --config ./.sourcery.yml --verbose \ No newline at end of file + sourcery --config ./.sourcery.yml --verbose +generateTestsCode: + sourcery --config ./.sourceryTests.yml --verbose \ No newline at end of file diff --git a/Tests/FirebladeECSTests/Generated/.gitkeep b/Tests/FirebladeECSTests/Generated/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil b/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil new file mode 100644 index 0000000..85bf0bb --- /dev/null +++ b/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil @@ -0,0 +1,156 @@ +import FirebladeECS +import XCTest + +{% for idx in 1...8 %} +{% map 1...idx into components using index %}Comp{{ index }}{% endmap %} +{% set CompParams %}{{components|join: ", "}}{% endset %} +{% map components into compWhere using comp %}{{ comp }}: Component{% endmap %} +{% set CompsWhere %}{{compWhere|join: ", "}}{% endset %} +{% map components into compEncodable using comp %}{{ comp }}: Encodable{% endmap %} +{% set CompsWhereEncodable %}{{compEncodable|join: ", "}}{% endset %} +{% map components into compsDecodable using comp %}{{ comp }}: Decodable{% endmap %} +{% set CompsWhereDecodable %}{{compsDecodable|join: ", "}}{% endset %} +{% map components into compTypes using comp %}{{ comp }}.Type{% endmap %} +{% set CompsTypes %}{{compTypes|join: ", "}}{% endset %} +{% map components into compSelf using comp %}{{ comp }}.self{% endmap %} +{% set CompsSelf %}{{compSelf|join: ", "}}{% endset %} +{% map components into compsLowercased using comp %}{{ comp|lowercase }}{% endmap %} +{% set CompsLowercased %}{{compsLowercased|join: ", "}}{% endset %} +{% map components into compsTuple using comp %}components.{{ maploop.counter }}{% endmap %} +{% set CompsTuple %}{{compsTuple|join: ", "}}{% endset %} +{% map components into compsParams using comp %}{% if not maploop.first %}_ {% endif %}{{ comp|lowercase }}: {{ comp }}.Type{% endmap %} +{% set CompsParams %}{{compsParams|join: ", "}}{% endset %} +{% map components into compsInstances using comp %}{{ comp }}({{ maploop.counter }}){% endmap %} +{% set CompsInstances %}{{compsInstances|join: ", "}}{% endset %} +{% map components into compsIndexedInstances using comp %}{{ comp }}({{ maploop.counter }}_000_000 + i){% endmap %} +{% set CompsIndexesInstances %}{{compsIndexedInstances|join: ", "}}{% endset %} +// MARK: - Family {{ idx }} test case +final class Family{{ idx }}Tests: XCTestCase { + var nexus: Nexus! + + override func setUp() { + super.setUp() + nexus = Nexus() + } + + func testMemberCreation() { + let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) + XCTAssertTrue(family.isEmpty) + let entity = family.createMember(with: ({{ CompsInstances }})) + XCTAssertEqual(family.count, 1) + XCTAssertEqual(entity.numComponents, {{ idx }}) + XCTAssertEqual(nexus.numFamilies, 1) + XCTAssertEqual(nexus.numEntities, 1) + XCTAssertEqual(nexus.numComponents, {{ idx }}) + {% for comp in components %} + XCTAssertEqual(entity[\{{ comp }}.value], {{ forloop.counter0 }}) + {% endfor %} + } + + func testComponentIteration() { + let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: ({{ CompsIndexesInstances }})) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.forEach { ({{ CompsLowercased }}) in + {% for comp in compsLowercased %} + XCTAssertEqual({{ comp }}.value, {{ forloop.counter0 }}_000_000 + idx) + {% endfor %} + idx += 1 + } + } + + func testEntityIteration() { + let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: ({{ CompsIndexesInstances }})) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entities.forEach { (entity) in + XCTAssertEqual(entity.numComponents, {{ idx }}) + {% for comp in components %} + XCTAssertNotNil(entity[\{{ comp }}.self]) + XCTAssertEqual(entity[\{{ comp }}.value], {{ forloop.counter0 }}_000_000 + idx) + {% endfor %} + idx += 1 + } + } + + func testEntityComponentIteration() { + let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: ({{ CompsIndexesInstances }})) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entityAndComponents.forEach { (entity, {{ CompsLowercased }}) in + XCTAssertEqual(entity.numComponents, {{ idx }}) + {% for comp in components %} + XCTAssertEqual({{ comp|lowercase }}.value, {{ forloop.counter0 }}_000_000 + idx) + XCTAssertEqual(entity[\{{ comp }}.self], {{ comp|lowercase }}) + {% endfor %} + idx += 1 + } + } + + func testFamilyEncoding() throws { + let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) + XCTAssertTrue(family.isEmpty) + for i in 0..<100 { + family.createMember(with: ({{ CompsIndexesInstances }})) + } + XCTAssertEqual(family.count, 100) + + var jsonEncoder = JSONEncoder() + let encodedData = try family.encodeMembers(using: &jsonEncoder) + XCTAssertGreaterThan(encodedData.count, 10) + guard let jsonString = String(data: encodedData, encoding: .utf8) else { + XCTFail("Failed to read string from encoded data \(encodedData.count)") + return + } + + let expectedStart = "[{" + XCTAssertEqual(String(jsonString.prefix(expectedStart.count)), String(expectedStart)) + let expectedEnd = "}]" + XCTAssertEqual(String(jsonString.suffix(expectedEnd.count)), String(expectedEnd)) + } + + func testFamilyDecoding() throws { + let jsonString: String = """ + [] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + let newEntities = try family.decodeMembers(from: jsonData, using: &jsonDecoder) + XCTAssertEqual(newEntities.count, 2) + XCTAssertEqual(family.count, 2) + } +} + +{% endfor %} + +// MARK: - Components +{% for idx in 1...8 %} +final class Comp{{ idx }}: Component { + var value: Int + init(_ value: Int) { self.value = value } +} +extension Comp{{ idx }}: Equatable { + static func == (lhs: Comp{{ idx }}, rhs: Comp{{ idx }}) -> Bool { + lhs === rhs && lhs.value == rhs.value + } + } +extension Comp{{ idx }}: Codable { } + +{% endfor %} \ No newline at end of file From 946d92f016bb3b2943b2aeb7452465ac9e5db474 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Wed, 5 Aug 2020 16:11:10 +0200 Subject: [PATCH 17/21] Add family tests stencil --- .sourceryTests.yml | 6 + Makefile | 6 +- Tests/FirebladeECSTests/Generated/.gitkeep | 0 .../Stencils/FamilyTests.stencil | 158 ++++++++++++++++++ 4 files changed, 168 insertions(+), 2 deletions(-) create mode 100644 .sourceryTests.yml create mode 100644 Tests/FirebladeECSTests/Generated/.gitkeep create mode 100644 Tests/FirebladeECSTests/Stencils/FamilyTests.stencil diff --git a/.sourceryTests.yml b/.sourceryTests.yml new file mode 100644 index 0000000..80db363 --- /dev/null +++ b/.sourceryTests.yml @@ -0,0 +1,6 @@ +sources: # you can provide either single path or several paths using `-` + - Sources +templates: # as well as for templates + - Tests/FirebladeECSTests/Stencils +output: # note that there is no `-` here as only single output path is supported + Tests/FirebladeECSTests/Generated diff --git a/Makefile b/Makefile index d95052b..f30b7b3 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ lintErrorOnly: @swiftlint lint --quiet | grep error # Git -precommit: generateCode lint genLinuxTests +precommit: generateCode generateTestsCode lint genLinuxTests submodule: git submodule init @@ -62,4 +62,6 @@ setupEnvironment: brew install sourcery generateCode: - sourcery --config ./.sourcery.yml --verbose \ No newline at end of file + sourcery --config ./.sourcery.yml --verbose +generateTestsCode: + sourcery --config ./.sourceryTests.yml --verbose \ No newline at end of file diff --git a/Tests/FirebladeECSTests/Generated/.gitkeep b/Tests/FirebladeECSTests/Generated/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil b/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil new file mode 100644 index 0000000..8c9a357 --- /dev/null +++ b/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil @@ -0,0 +1,158 @@ +import FirebladeECS +import XCTest + +{% for idx in 1...8 %} +{% map 1...idx into components using index %}Comp{{ index }}{% endmap %} +{% set CompParams %}{{components|join: ", "}}{% endset %} +{% map components into compWhere using comp %}{{ comp }}: Component{% endmap %} +{% set CompsWhere %}{{compWhere|join: ", "}}{% endset %} +{% map components into compEncodable using comp %}{{ comp }}: Encodable{% endmap %} +{% set CompsWhereEncodable %}{{compEncodable|join: ", "}}{% endset %} +{% map components into compsDecodable using comp %}{{ comp }}: Decodable{% endmap %} +{% set CompsWhereDecodable %}{{compsDecodable|join: ", "}}{% endset %} +{% map components into compTypes using comp %}{{ comp }}.Type{% endmap %} +{% set CompsTypes %}{{compTypes|join: ", "}}{% endset %} +{% map components into compSelf using comp %}{{ comp }}.self{% endmap %} +{% set CompsSelf %}{{compSelf|join: ", "}}{% endset %} +{% map components into compsLowercased using comp %}{{ comp|lowercase }}{% endmap %} +{% set CompsLowercased %}{{compsLowercased|join: ", "}}{% endset %} +{% map components into compsTuple using comp %}components.{{ maploop.counter }}{% endmap %} +{% set CompsTuple %}{{compsTuple|join: ", "}}{% endset %} +{% map components into compsParams using comp %}{% if not maploop.first %}_ {% endif %}{{ comp|lowercase }}: {{ comp }}.Type{% endmap %} +{% set CompsParams %}{{compsParams|join: ", "}}{% endset %} +{% map components into compsInstances using comp %}{{ comp }}({{ maploop.counter }}){% endmap %} +{% set CompsInstances %}{{compsInstances|join: ", "}}{% endset %} +{% map components into compsIndexedInstances using comp %}{{ comp }}({{ maploop.counter }}_000_000 + i){% endmap %} +{% set CompsIndexesInstances %}{{compsIndexedInstances|join: ", "}}{% endset %} +{% map components into compsJsonInner using comp %}"{{ comp }}":{ "value" : {{ maploop.counter }} }{% endmap %} +{% map 0...2 into compsJson %}{ {{compsJsonInner|join: ","}} }{% endmap %} +// MARK: - Family {{ idx }} test case +final class Family{{ idx }}Tests: XCTestCase { + var nexus: Nexus! + + override func setUp() { + super.setUp() + nexus = Nexus() + } + + func testMemberCreation() { + let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) + XCTAssertTrue(family.isEmpty) + let entity = family.createMember(with: ({{ CompsInstances }})) + XCTAssertEqual(family.count, 1) + XCTAssertEqual(entity.numComponents, {{ idx }}) + XCTAssertEqual(nexus.numFamilies, 1) + XCTAssertEqual(nexus.numEntities, 1) + XCTAssertEqual(nexus.numComponents, {{ idx }}) + {% for comp in components %} + XCTAssertEqual(entity[\{{ comp }}.value], {{ forloop.counter0 }}) + {% endfor %} + } + + func testComponentIteration() { + let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: ({{ CompsIndexesInstances }})) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.forEach { ({{ CompsLowercased }}) in + {% for comp in compsLowercased %} + XCTAssertEqual({{ comp }}.value, {{ forloop.counter0 }}_000_000 + idx) + {% endfor %} + idx += 1 + } + } + + func testEntityIteration() { + let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: ({{ CompsIndexesInstances }})) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entities.forEach { (entity) in + XCTAssertEqual(entity.numComponents, {{ idx }}) + {% for comp in components %} + XCTAssertNotNil(entity[\{{ comp }}.self]) + XCTAssertEqual(entity[\{{ comp }}.value], {{ forloop.counter0 }}_000_000 + idx) + {% endfor %} + idx += 1 + } + } + + func testEntityComponentIteration() { + let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: ({{ CompsIndexesInstances }})) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entityAndComponents.forEach { (entity, {{ CompsLowercased }}) in + XCTAssertEqual(entity.numComponents, {{ idx }}) + {% for comp in components %} + XCTAssertEqual({{ comp|lowercase }}.value, {{ forloop.counter0 }}_000_000 + idx) + XCTAssertEqual(entity[\{{ comp }}.self], {{ comp|lowercase }}) + {% endfor %} + idx += 1 + } + } + + func testFamilyEncoding() throws { + let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) + XCTAssertTrue(family.isEmpty) + for i in 0..<100 { + family.createMember(with: ({{ CompsIndexesInstances }})) + } + XCTAssertEqual(family.count, 100) + + var jsonEncoder = JSONEncoder() + let encodedData = try family.encodeMembers(using: &jsonEncoder) + XCTAssertGreaterThan(encodedData.count, 10) + guard let jsonString = String(data: encodedData, encoding: .utf8) else { + XCTFail("Failed to read string from encoded data \(encodedData.count)") + return + } + + let expectedStart = "[{" + XCTAssertEqual(String(jsonString.prefix(expectedStart.count)), String(expectedStart)) + let expectedEnd = "}]" + XCTAssertEqual(String(jsonString.suffix(expectedEnd.count)), String(expectedEnd)) + } + + func testFamilyDecoding() throws { + let jsonString: String = """ + [ {{compsJson|join: ", "}} ] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + let newEntities = try family.decodeMembers(from: jsonData, using: &jsonDecoder) + XCTAssertEqual(newEntities.count, 3) + XCTAssertEqual(family.count, 3) + } +} + +{% endfor %} + +// MARK: - Components +{% for idx in 1...8 %} +final class Comp{{ idx }}: Component { + var value: Int + init(_ value: Int) { self.value = value } +} +extension Comp{{ idx }}: Equatable { + static func == (lhs: Comp{{ idx }}, rhs: Comp{{ idx }}) -> Bool { + lhs === rhs && lhs.value == rhs.value + } + } +extension Comp{{ idx }}: Codable { } + +{% endfor %} \ No newline at end of file From 602d87a9a08db07300b2245670bb53baf65008d4 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Wed, 5 Aug 2020 18:06:34 +0200 Subject: [PATCH 18/21] Generate tests --- .../Generated/FamilyTests.generated.swift | 1102 +++++++++++++++++ Tests/FirebladeECSTests/XCTestManifests.swift | 120 ++ 2 files changed, 1222 insertions(+) create mode 100644 Tests/FirebladeECSTests/Generated/FamilyTests.generated.swift diff --git a/Tests/FirebladeECSTests/Generated/FamilyTests.generated.swift b/Tests/FirebladeECSTests/Generated/FamilyTests.generated.swift new file mode 100644 index 0000000..10d8611 --- /dev/null +++ b/Tests/FirebladeECSTests/Generated/FamilyTests.generated.swift @@ -0,0 +1,1102 @@ +// Generated using Sourcery 0.18.0 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT + +import FirebladeECS +import XCTest + +// MARK: - Family 1 test case +final class Family1Tests: XCTestCase { + var nexus: Nexus! + + override func setUp() { + super.setUp() + nexus = Nexus() + } + + func testMemberCreation() { + let family = nexus.family(requires: Comp1.self) + XCTAssertTrue(family.isEmpty) + let entity = family.createMember(with: (Comp1(0))) + XCTAssertEqual(family.count, 1) + XCTAssertEqual(entity.numComponents, 1) + XCTAssertEqual(nexus.numFamilies, 1) + XCTAssertEqual(nexus.numEntities, 1) + XCTAssertEqual(nexus.numComponents, 1) + XCTAssertEqual(entity[\Comp1.value], 0) + } + + func testComponentIteration() { + let family = nexus.family(requires: Comp1.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.forEach { (comp1) in + XCTAssertEqual(comp1.value, 0_000_000 + idx) + idx += 1 + } + } + + func testEntityIteration() { + let family = nexus.family(requires: Comp1.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entities.forEach { (entity) in + XCTAssertEqual(entity.numComponents, 1) + XCTAssertNotNil(entity[\Comp1.self]) + XCTAssertEqual(entity[\Comp1.value], 0_000_000 + idx) + idx += 1 + } + } + + func testEntityComponentIteration() { + let family = nexus.family(requires: Comp1.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entityAndComponents.forEach { (entity, comp1) in + XCTAssertEqual(entity.numComponents, 1) + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(entity[\Comp1.self], comp1) + idx += 1 + } + } + + func testFamilyEncoding() throws { + let family = nexus.family(requires: Comp1.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<100 { + family.createMember(with: (Comp1(0_000_000 + i))) + } + XCTAssertEqual(family.count, 100) + + var jsonEncoder = JSONEncoder() + let encodedData = try family.encodeMembers(using: &jsonEncoder) + XCTAssertGreaterThan(encodedData.count, 10) + guard let jsonString = String(data: encodedData, encoding: .utf8) else { + XCTFail("Failed to read string from encoded data \(encodedData.count)") + return + } + let expectedStart = "[{" + XCTAssertEqual(String(jsonString.prefix(expectedStart.count)), String(expectedStart)) + let expectedEnd = "}]" + XCTAssertEqual(String(jsonString.suffix(expectedEnd.count)), String(expectedEnd)) + } + + func testFamilyDecoding() throws { + let jsonString: String = """ + [ { "Comp1":{ "value" : 0 } }, { "Comp1":{ "value" : 0 } }, { "Comp1":{ "value" : 0 } } ] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requires: Comp1.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + let newEntities = try family.decodeMembers(from: jsonData, using: &jsonDecoder) + XCTAssertEqual(newEntities.count, 3) + XCTAssertEqual(family.count, 3) + } +} + +// MARK: - Family 2 test case +final class Family2Tests: XCTestCase { + var nexus: Nexus! + + override func setUp() { + super.setUp() + nexus = Nexus() + } + + func testMemberCreation() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self) + XCTAssertTrue(family.isEmpty) + let entity = family.createMember(with: (Comp1(0), Comp2(1))) + XCTAssertEqual(family.count, 1) + XCTAssertEqual(entity.numComponents, 2) + XCTAssertEqual(nexus.numFamilies, 1) + XCTAssertEqual(nexus.numEntities, 1) + XCTAssertEqual(nexus.numComponents, 2) + XCTAssertEqual(entity[\Comp1.value], 0) + XCTAssertEqual(entity[\Comp2.value], 1) + } + + func testComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.forEach { (comp1, comp2) in + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + idx += 1 + } + } + + func testEntityIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entities.forEach { (entity) in + XCTAssertEqual(entity.numComponents, 2) + XCTAssertNotNil(entity[\Comp1.self]) + XCTAssertEqual(entity[\Comp1.value], 0_000_000 + idx) + XCTAssertNotNil(entity[\Comp2.self]) + XCTAssertEqual(entity[\Comp2.value], 1_000_000 + idx) + idx += 1 + } + } + + func testEntityComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entityAndComponents.forEach { (entity, comp1, comp2) in + XCTAssertEqual(entity.numComponents, 2) + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(entity[\Comp1.self], comp1) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + XCTAssertEqual(entity[\Comp2.self], comp2) + idx += 1 + } + } + + func testFamilyEncoding() throws { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<100 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i))) + } + XCTAssertEqual(family.count, 100) + + var jsonEncoder = JSONEncoder() + let encodedData = try family.encodeMembers(using: &jsonEncoder) + XCTAssertGreaterThan(encodedData.count, 10) + guard let jsonString = String(data: encodedData, encoding: .utf8) else { + XCTFail("Failed to read string from encoded data \(encodedData.count)") + return + } + let expectedStart = "[{" + XCTAssertEqual(String(jsonString.prefix(expectedStart.count)), String(expectedStart)) + let expectedEnd = "}]" + XCTAssertEqual(String(jsonString.suffix(expectedEnd.count)), String(expectedEnd)) + } + + func testFamilyDecoding() throws { + let jsonString: String = """ + [ { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 } } ] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + let newEntities = try family.decodeMembers(from: jsonData, using: &jsonDecoder) + XCTAssertEqual(newEntities.count, 3) + XCTAssertEqual(family.count, 3) + } +} + +// MARK: - Family 3 test case +final class Family3Tests: XCTestCase { + var nexus: Nexus! + + override func setUp() { + super.setUp() + nexus = Nexus() + } + + func testMemberCreation() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self) + XCTAssertTrue(family.isEmpty) + let entity = family.createMember(with: (Comp1(0), Comp2(1), Comp3(2))) + XCTAssertEqual(family.count, 1) + XCTAssertEqual(entity.numComponents, 3) + XCTAssertEqual(nexus.numFamilies, 1) + XCTAssertEqual(nexus.numEntities, 1) + XCTAssertEqual(nexus.numComponents, 3) + XCTAssertEqual(entity[\Comp1.value], 0) + XCTAssertEqual(entity[\Comp2.value], 1) + XCTAssertEqual(entity[\Comp3.value], 2) + } + + func testComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.forEach { (comp1, comp2, comp3) in + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + XCTAssertEqual(comp3.value, 2_000_000 + idx) + idx += 1 + } + } + + func testEntityIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entities.forEach { (entity) in + XCTAssertEqual(entity.numComponents, 3) + XCTAssertNotNil(entity[\Comp1.self]) + XCTAssertEqual(entity[\Comp1.value], 0_000_000 + idx) + XCTAssertNotNil(entity[\Comp2.self]) + XCTAssertEqual(entity[\Comp2.value], 1_000_000 + idx) + XCTAssertNotNil(entity[\Comp3.self]) + XCTAssertEqual(entity[\Comp3.value], 2_000_000 + idx) + idx += 1 + } + } + + func testEntityComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entityAndComponents.forEach { (entity, comp1, comp2, comp3) in + XCTAssertEqual(entity.numComponents, 3) + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(entity[\Comp1.self], comp1) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + XCTAssertEqual(entity[\Comp2.self], comp2) + XCTAssertEqual(comp3.value, 2_000_000 + idx) + XCTAssertEqual(entity[\Comp3.self], comp3) + idx += 1 + } + } + + func testFamilyEncoding() throws { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<100 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i))) + } + XCTAssertEqual(family.count, 100) + + var jsonEncoder = JSONEncoder() + let encodedData = try family.encodeMembers(using: &jsonEncoder) + XCTAssertGreaterThan(encodedData.count, 10) + guard let jsonString = String(data: encodedData, encoding: .utf8) else { + XCTFail("Failed to read string from encoded data \(encodedData.count)") + return + } + let expectedStart = "[{" + XCTAssertEqual(String(jsonString.prefix(expectedStart.count)), String(expectedStart)) + let expectedEnd = "}]" + XCTAssertEqual(String(jsonString.suffix(expectedEnd.count)), String(expectedEnd)) + } + + func testFamilyDecoding() throws { + let jsonString: String = """ + [ { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 } } ] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + let newEntities = try family.decodeMembers(from: jsonData, using: &jsonDecoder) + XCTAssertEqual(newEntities.count, 3) + XCTAssertEqual(family.count, 3) + } +} + +// MARK: - Family 4 test case +final class Family4Tests: XCTestCase { + var nexus: Nexus! + + override func setUp() { + super.setUp() + nexus = Nexus() + } + + func testMemberCreation() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self) + XCTAssertTrue(family.isEmpty) + let entity = family.createMember(with: (Comp1(0), Comp2(1), Comp3(2), Comp4(3))) + XCTAssertEqual(family.count, 1) + XCTAssertEqual(entity.numComponents, 4) + XCTAssertEqual(nexus.numFamilies, 1) + XCTAssertEqual(nexus.numEntities, 1) + XCTAssertEqual(nexus.numComponents, 4) + XCTAssertEqual(entity[\Comp1.value], 0) + XCTAssertEqual(entity[\Comp2.value], 1) + XCTAssertEqual(entity[\Comp3.value], 2) + XCTAssertEqual(entity[\Comp4.value], 3) + } + + func testComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.forEach { (comp1, comp2, comp3, comp4) in + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + XCTAssertEqual(comp3.value, 2_000_000 + idx) + XCTAssertEqual(comp4.value, 3_000_000 + idx) + idx += 1 + } + } + + func testEntityIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entities.forEach { (entity) in + XCTAssertEqual(entity.numComponents, 4) + XCTAssertNotNil(entity[\Comp1.self]) + XCTAssertEqual(entity[\Comp1.value], 0_000_000 + idx) + XCTAssertNotNil(entity[\Comp2.self]) + XCTAssertEqual(entity[\Comp2.value], 1_000_000 + idx) + XCTAssertNotNil(entity[\Comp3.self]) + XCTAssertEqual(entity[\Comp3.value], 2_000_000 + idx) + XCTAssertNotNil(entity[\Comp4.self]) + XCTAssertEqual(entity[\Comp4.value], 3_000_000 + idx) + idx += 1 + } + } + + func testEntityComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entityAndComponents.forEach { (entity, comp1, comp2, comp3, comp4) in + XCTAssertEqual(entity.numComponents, 4) + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(entity[\Comp1.self], comp1) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + XCTAssertEqual(entity[\Comp2.self], comp2) + XCTAssertEqual(comp3.value, 2_000_000 + idx) + XCTAssertEqual(entity[\Comp3.self], comp3) + XCTAssertEqual(comp4.value, 3_000_000 + idx) + XCTAssertEqual(entity[\Comp4.self], comp4) + idx += 1 + } + } + + func testFamilyEncoding() throws { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<100 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i))) + } + XCTAssertEqual(family.count, 100) + + var jsonEncoder = JSONEncoder() + let encodedData = try family.encodeMembers(using: &jsonEncoder) + XCTAssertGreaterThan(encodedData.count, 10) + guard let jsonString = String(data: encodedData, encoding: .utf8) else { + XCTFail("Failed to read string from encoded data \(encodedData.count)") + return + } + let expectedStart = "[{" + XCTAssertEqual(String(jsonString.prefix(expectedStart.count)), String(expectedStart)) + let expectedEnd = "}]" + XCTAssertEqual(String(jsonString.suffix(expectedEnd.count)), String(expectedEnd)) + } + + func testFamilyDecoding() throws { + let jsonString: String = """ + [ { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 } } ] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + let newEntities = try family.decodeMembers(from: jsonData, using: &jsonDecoder) + XCTAssertEqual(newEntities.count, 3) + XCTAssertEqual(family.count, 3) + } +} + +// MARK: - Family 5 test case +final class Family5Tests: XCTestCase { + var nexus: Nexus! + + override func setUp() { + super.setUp() + nexus = Nexus() + } + + func testMemberCreation() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self) + XCTAssertTrue(family.isEmpty) + let entity = family.createMember(with: (Comp1(0), Comp2(1), Comp3(2), Comp4(3), Comp5(4))) + XCTAssertEqual(family.count, 1) + XCTAssertEqual(entity.numComponents, 5) + XCTAssertEqual(nexus.numFamilies, 1) + XCTAssertEqual(nexus.numEntities, 1) + XCTAssertEqual(nexus.numComponents, 5) + XCTAssertEqual(entity[\Comp1.value], 0) + XCTAssertEqual(entity[\Comp2.value], 1) + XCTAssertEqual(entity[\Comp3.value], 2) + XCTAssertEqual(entity[\Comp4.value], 3) + XCTAssertEqual(entity[\Comp5.value], 4) + } + + func testComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.forEach { (comp1, comp2, comp3, comp4, comp5) in + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + XCTAssertEqual(comp3.value, 2_000_000 + idx) + XCTAssertEqual(comp4.value, 3_000_000 + idx) + XCTAssertEqual(comp5.value, 4_000_000 + idx) + idx += 1 + } + } + + func testEntityIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entities.forEach { (entity) in + XCTAssertEqual(entity.numComponents, 5) + XCTAssertNotNil(entity[\Comp1.self]) + XCTAssertEqual(entity[\Comp1.value], 0_000_000 + idx) + XCTAssertNotNil(entity[\Comp2.self]) + XCTAssertEqual(entity[\Comp2.value], 1_000_000 + idx) + XCTAssertNotNil(entity[\Comp3.self]) + XCTAssertEqual(entity[\Comp3.value], 2_000_000 + idx) + XCTAssertNotNil(entity[\Comp4.self]) + XCTAssertEqual(entity[\Comp4.value], 3_000_000 + idx) + XCTAssertNotNil(entity[\Comp5.self]) + XCTAssertEqual(entity[\Comp5.value], 4_000_000 + idx) + idx += 1 + } + } + + func testEntityComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entityAndComponents.forEach { (entity, comp1, comp2, comp3, comp4, comp5) in + XCTAssertEqual(entity.numComponents, 5) + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(entity[\Comp1.self], comp1) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + XCTAssertEqual(entity[\Comp2.self], comp2) + XCTAssertEqual(comp3.value, 2_000_000 + idx) + XCTAssertEqual(entity[\Comp3.self], comp3) + XCTAssertEqual(comp4.value, 3_000_000 + idx) + XCTAssertEqual(entity[\Comp4.self], comp4) + XCTAssertEqual(comp5.value, 4_000_000 + idx) + XCTAssertEqual(entity[\Comp5.self], comp5) + idx += 1 + } + } + + func testFamilyEncoding() throws { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<100 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i))) + } + XCTAssertEqual(family.count, 100) + + var jsonEncoder = JSONEncoder() + let encodedData = try family.encodeMembers(using: &jsonEncoder) + XCTAssertGreaterThan(encodedData.count, 10) + guard let jsonString = String(data: encodedData, encoding: .utf8) else { + XCTFail("Failed to read string from encoded data \(encodedData.count)") + return + } + let expectedStart = "[{" + XCTAssertEqual(String(jsonString.prefix(expectedStart.count)), String(expectedStart)) + let expectedEnd = "}]" + XCTAssertEqual(String(jsonString.suffix(expectedEnd.count)), String(expectedEnd)) + } + + func testFamilyDecoding() throws { + let jsonString: String = """ + [ { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 },"Comp5":{ "value" : 4 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 },"Comp5":{ "value" : 4 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 },"Comp5":{ "value" : 4 } } ] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + let newEntities = try family.decodeMembers(from: jsonData, using: &jsonDecoder) + XCTAssertEqual(newEntities.count, 3) + XCTAssertEqual(family.count, 3) + } +} + +// MARK: - Family 6 test case +final class Family6Tests: XCTestCase { + var nexus: Nexus! + + override func setUp() { + super.setUp() + nexus = Nexus() + } + + func testMemberCreation() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self) + XCTAssertTrue(family.isEmpty) + let entity = family.createMember(with: (Comp1(0), Comp2(1), Comp3(2), Comp4(3), Comp5(4), Comp6(5))) + XCTAssertEqual(family.count, 1) + XCTAssertEqual(entity.numComponents, 6) + XCTAssertEqual(nexus.numFamilies, 1) + XCTAssertEqual(nexus.numEntities, 1) + XCTAssertEqual(nexus.numComponents, 6) + XCTAssertEqual(entity[\Comp1.value], 0) + XCTAssertEqual(entity[\Comp2.value], 1) + XCTAssertEqual(entity[\Comp3.value], 2) + XCTAssertEqual(entity[\Comp4.value], 3) + XCTAssertEqual(entity[\Comp5.value], 4) + XCTAssertEqual(entity[\Comp6.value], 5) + } + + func testComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i), Comp6(5_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6) in + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + XCTAssertEqual(comp3.value, 2_000_000 + idx) + XCTAssertEqual(comp4.value, 3_000_000 + idx) + XCTAssertEqual(comp5.value, 4_000_000 + idx) + XCTAssertEqual(comp6.value, 5_000_000 + idx) + idx += 1 + } + } + + func testEntityIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i), Comp6(5_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entities.forEach { (entity) in + XCTAssertEqual(entity.numComponents, 6) + XCTAssertNotNil(entity[\Comp1.self]) + XCTAssertEqual(entity[\Comp1.value], 0_000_000 + idx) + XCTAssertNotNil(entity[\Comp2.self]) + XCTAssertEqual(entity[\Comp2.value], 1_000_000 + idx) + XCTAssertNotNil(entity[\Comp3.self]) + XCTAssertEqual(entity[\Comp3.value], 2_000_000 + idx) + XCTAssertNotNil(entity[\Comp4.self]) + XCTAssertEqual(entity[\Comp4.value], 3_000_000 + idx) + XCTAssertNotNil(entity[\Comp5.self]) + XCTAssertEqual(entity[\Comp5.value], 4_000_000 + idx) + XCTAssertNotNil(entity[\Comp6.self]) + XCTAssertEqual(entity[\Comp6.value], 5_000_000 + idx) + idx += 1 + } + } + + func testEntityComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i), Comp6(5_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entityAndComponents.forEach { (entity, comp1, comp2, comp3, comp4, comp5, comp6) in + XCTAssertEqual(entity.numComponents, 6) + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(entity[\Comp1.self], comp1) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + XCTAssertEqual(entity[\Comp2.self], comp2) + XCTAssertEqual(comp3.value, 2_000_000 + idx) + XCTAssertEqual(entity[\Comp3.self], comp3) + XCTAssertEqual(comp4.value, 3_000_000 + idx) + XCTAssertEqual(entity[\Comp4.self], comp4) + XCTAssertEqual(comp5.value, 4_000_000 + idx) + XCTAssertEqual(entity[\Comp5.self], comp5) + XCTAssertEqual(comp6.value, 5_000_000 + idx) + XCTAssertEqual(entity[\Comp6.self], comp6) + idx += 1 + } + } + + func testFamilyEncoding() throws { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<100 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i), Comp6(5_000_000 + i))) + } + XCTAssertEqual(family.count, 100) + + var jsonEncoder = JSONEncoder() + let encodedData = try family.encodeMembers(using: &jsonEncoder) + XCTAssertGreaterThan(encodedData.count, 10) + guard let jsonString = String(data: encodedData, encoding: .utf8) else { + XCTFail("Failed to read string from encoded data \(encodedData.count)") + return + } + let expectedStart = "[{" + XCTAssertEqual(String(jsonString.prefix(expectedStart.count)), String(expectedStart)) + let expectedEnd = "}]" + XCTAssertEqual(String(jsonString.suffix(expectedEnd.count)), String(expectedEnd)) + } + + func testFamilyDecoding() throws { + let jsonString: String = """ + [ { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 },"Comp5":{ "value" : 4 },"Comp6":{ "value" : 5 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 },"Comp5":{ "value" : 4 },"Comp6":{ "value" : 5 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 },"Comp5":{ "value" : 4 },"Comp6":{ "value" : 5 } } ] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + let newEntities = try family.decodeMembers(from: jsonData, using: &jsonDecoder) + XCTAssertEqual(newEntities.count, 3) + XCTAssertEqual(family.count, 3) + } +} + +// MARK: - Family 7 test case +final class Family7Tests: XCTestCase { + var nexus: Nexus! + + override func setUp() { + super.setUp() + nexus = Nexus() + } + + func testMemberCreation() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self) + XCTAssertTrue(family.isEmpty) + let entity = family.createMember(with: (Comp1(0), Comp2(1), Comp3(2), Comp4(3), Comp5(4), Comp6(5), Comp7(6))) + XCTAssertEqual(family.count, 1) + XCTAssertEqual(entity.numComponents, 7) + XCTAssertEqual(nexus.numFamilies, 1) + XCTAssertEqual(nexus.numEntities, 1) + XCTAssertEqual(nexus.numComponents, 7) + XCTAssertEqual(entity[\Comp1.value], 0) + XCTAssertEqual(entity[\Comp2.value], 1) + XCTAssertEqual(entity[\Comp3.value], 2) + XCTAssertEqual(entity[\Comp4.value], 3) + XCTAssertEqual(entity[\Comp5.value], 4) + XCTAssertEqual(entity[\Comp6.value], 5) + XCTAssertEqual(entity[\Comp7.value], 6) + } + + func testComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i), Comp6(5_000_000 + i), Comp7(6_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7) in + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + XCTAssertEqual(comp3.value, 2_000_000 + idx) + XCTAssertEqual(comp4.value, 3_000_000 + idx) + XCTAssertEqual(comp5.value, 4_000_000 + idx) + XCTAssertEqual(comp6.value, 5_000_000 + idx) + XCTAssertEqual(comp7.value, 6_000_000 + idx) + idx += 1 + } + } + + func testEntityIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i), Comp6(5_000_000 + i), Comp7(6_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entities.forEach { (entity) in + XCTAssertEqual(entity.numComponents, 7) + XCTAssertNotNil(entity[\Comp1.self]) + XCTAssertEqual(entity[\Comp1.value], 0_000_000 + idx) + XCTAssertNotNil(entity[\Comp2.self]) + XCTAssertEqual(entity[\Comp2.value], 1_000_000 + idx) + XCTAssertNotNil(entity[\Comp3.self]) + XCTAssertEqual(entity[\Comp3.value], 2_000_000 + idx) + XCTAssertNotNil(entity[\Comp4.self]) + XCTAssertEqual(entity[\Comp4.value], 3_000_000 + idx) + XCTAssertNotNil(entity[\Comp5.self]) + XCTAssertEqual(entity[\Comp5.value], 4_000_000 + idx) + XCTAssertNotNil(entity[\Comp6.self]) + XCTAssertEqual(entity[\Comp6.value], 5_000_000 + idx) + XCTAssertNotNil(entity[\Comp7.self]) + XCTAssertEqual(entity[\Comp7.value], 6_000_000 + idx) + idx += 1 + } + } + + func testEntityComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i), Comp6(5_000_000 + i), Comp7(6_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entityAndComponents.forEach { (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7) in + XCTAssertEqual(entity.numComponents, 7) + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(entity[\Comp1.self], comp1) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + XCTAssertEqual(entity[\Comp2.self], comp2) + XCTAssertEqual(comp3.value, 2_000_000 + idx) + XCTAssertEqual(entity[\Comp3.self], comp3) + XCTAssertEqual(comp4.value, 3_000_000 + idx) + XCTAssertEqual(entity[\Comp4.self], comp4) + XCTAssertEqual(comp5.value, 4_000_000 + idx) + XCTAssertEqual(entity[\Comp5.self], comp5) + XCTAssertEqual(comp6.value, 5_000_000 + idx) + XCTAssertEqual(entity[\Comp6.self], comp6) + XCTAssertEqual(comp7.value, 6_000_000 + idx) + XCTAssertEqual(entity[\Comp7.self], comp7) + idx += 1 + } + } + + func testFamilyEncoding() throws { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<100 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i), Comp6(5_000_000 + i), Comp7(6_000_000 + i))) + } + XCTAssertEqual(family.count, 100) + + var jsonEncoder = JSONEncoder() + let encodedData = try family.encodeMembers(using: &jsonEncoder) + XCTAssertGreaterThan(encodedData.count, 10) + guard let jsonString = String(data: encodedData, encoding: .utf8) else { + XCTFail("Failed to read string from encoded data \(encodedData.count)") + return + } + let expectedStart = "[{" + XCTAssertEqual(String(jsonString.prefix(expectedStart.count)), String(expectedStart)) + let expectedEnd = "}]" + XCTAssertEqual(String(jsonString.suffix(expectedEnd.count)), String(expectedEnd)) + } + + func testFamilyDecoding() throws { + let jsonString: String = """ + [ { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 },"Comp5":{ "value" : 4 },"Comp6":{ "value" : 5 },"Comp7":{ "value" : 6 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 },"Comp5":{ "value" : 4 },"Comp6":{ "value" : 5 },"Comp7":{ "value" : 6 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 },"Comp5":{ "value" : 4 },"Comp6":{ "value" : 5 },"Comp7":{ "value" : 6 } } ] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + let newEntities = try family.decodeMembers(from: jsonData, using: &jsonDecoder) + XCTAssertEqual(newEntities.count, 3) + XCTAssertEqual(family.count, 3) + } +} + +// MARK: - Family 8 test case +final class Family8Tests: XCTestCase { + var nexus: Nexus! + + override func setUp() { + super.setUp() + nexus = Nexus() + } + + func testMemberCreation() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self) + XCTAssertTrue(family.isEmpty) + let entity = family.createMember(with: (Comp1(0), Comp2(1), Comp3(2), Comp4(3), Comp5(4), Comp6(5), Comp7(6), Comp8(7))) + XCTAssertEqual(family.count, 1) + XCTAssertEqual(entity.numComponents, 8) + XCTAssertEqual(nexus.numFamilies, 1) + XCTAssertEqual(nexus.numEntities, 1) + XCTAssertEqual(nexus.numComponents, 8) + XCTAssertEqual(entity[\Comp1.value], 0) + XCTAssertEqual(entity[\Comp2.value], 1) + XCTAssertEqual(entity[\Comp3.value], 2) + XCTAssertEqual(entity[\Comp4.value], 3) + XCTAssertEqual(entity[\Comp5.value], 4) + XCTAssertEqual(entity[\Comp6.value], 5) + XCTAssertEqual(entity[\Comp7.value], 6) + XCTAssertEqual(entity[\Comp8.value], 7) + } + + func testComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i), Comp6(5_000_000 + i), Comp7(6_000_000 + i), Comp8(7_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.forEach { (comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8) in + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + XCTAssertEqual(comp3.value, 2_000_000 + idx) + XCTAssertEqual(comp4.value, 3_000_000 + idx) + XCTAssertEqual(comp5.value, 4_000_000 + idx) + XCTAssertEqual(comp6.value, 5_000_000 + idx) + XCTAssertEqual(comp7.value, 6_000_000 + idx) + XCTAssertEqual(comp8.value, 7_000_000 + idx) + idx += 1 + } + } + + func testEntityIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i), Comp6(5_000_000 + i), Comp7(6_000_000 + i), Comp8(7_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entities.forEach { (entity) in + XCTAssertEqual(entity.numComponents, 8) + XCTAssertNotNil(entity[\Comp1.self]) + XCTAssertEqual(entity[\Comp1.value], 0_000_000 + idx) + XCTAssertNotNil(entity[\Comp2.self]) + XCTAssertEqual(entity[\Comp2.value], 1_000_000 + idx) + XCTAssertNotNil(entity[\Comp3.self]) + XCTAssertEqual(entity[\Comp3.value], 2_000_000 + idx) + XCTAssertNotNil(entity[\Comp4.self]) + XCTAssertEqual(entity[\Comp4.value], 3_000_000 + idx) + XCTAssertNotNil(entity[\Comp5.self]) + XCTAssertEqual(entity[\Comp5.value], 4_000_000 + idx) + XCTAssertNotNil(entity[\Comp6.self]) + XCTAssertEqual(entity[\Comp6.value], 5_000_000 + idx) + XCTAssertNotNil(entity[\Comp7.self]) + XCTAssertEqual(entity[\Comp7.value], 6_000_000 + idx) + XCTAssertNotNil(entity[\Comp8.self]) + XCTAssertEqual(entity[\Comp8.value], 7_000_000 + idx) + idx += 1 + } + } + + func testEntityComponentIteration() { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<10_000 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i), Comp6(5_000_000 + i), Comp7(6_000_000 + i), Comp8(7_000_000 + i))) + } + XCTAssertEqual(family.count, 10_000) + var idx: Int = 0 + family.entityAndComponents.forEach { (entity, comp1, comp2, comp3, comp4, comp5, comp6, comp7, comp8) in + XCTAssertEqual(entity.numComponents, 8) + XCTAssertEqual(comp1.value, 0_000_000 + idx) + XCTAssertEqual(entity[\Comp1.self], comp1) + XCTAssertEqual(comp2.value, 1_000_000 + idx) + XCTAssertEqual(entity[\Comp2.self], comp2) + XCTAssertEqual(comp3.value, 2_000_000 + idx) + XCTAssertEqual(entity[\Comp3.self], comp3) + XCTAssertEqual(comp4.value, 3_000_000 + idx) + XCTAssertEqual(entity[\Comp4.self], comp4) + XCTAssertEqual(comp5.value, 4_000_000 + idx) + XCTAssertEqual(entity[\Comp5.self], comp5) + XCTAssertEqual(comp6.value, 5_000_000 + idx) + XCTAssertEqual(entity[\Comp6.self], comp6) + XCTAssertEqual(comp7.value, 6_000_000 + idx) + XCTAssertEqual(entity[\Comp7.self], comp7) + XCTAssertEqual(comp8.value, 7_000_000 + idx) + XCTAssertEqual(entity[\Comp8.self], comp8) + idx += 1 + } + } + + func testFamilyEncoding() throws { + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self) + XCTAssertTrue(family.isEmpty) + for i in 0..<100 { + family.createMember(with: (Comp1(0_000_000 + i), Comp2(1_000_000 + i), Comp3(2_000_000 + i), Comp4(3_000_000 + i), Comp5(4_000_000 + i), Comp6(5_000_000 + i), Comp7(6_000_000 + i), Comp8(7_000_000 + i))) + } + XCTAssertEqual(family.count, 100) + + var jsonEncoder = JSONEncoder() + let encodedData = try family.encodeMembers(using: &jsonEncoder) + XCTAssertGreaterThan(encodedData.count, 10) + guard let jsonString = String(data: encodedData, encoding: .utf8) else { + XCTFail("Failed to read string from encoded data \(encodedData.count)") + return + } + let expectedStart = "[{" + XCTAssertEqual(String(jsonString.prefix(expectedStart.count)), String(expectedStart)) + let expectedEnd = "}]" + XCTAssertEqual(String(jsonString.suffix(expectedEnd.count)), String(expectedEnd)) + } + + func testFamilyDecoding() throws { + let jsonString: String = """ + [ { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 },"Comp5":{ "value" : 4 },"Comp6":{ "value" : 5 },"Comp7":{ "value" : 6 },"Comp8":{ "value" : 7 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 },"Comp5":{ "value" : 4 },"Comp6":{ "value" : 5 },"Comp7":{ "value" : 6 },"Comp8":{ "value" : 7 } }, { "Comp1":{ "value" : 0 },"Comp2":{ "value" : 1 },"Comp3":{ "value" : 2 },"Comp4":{ "value" : 3 },"Comp5":{ "value" : 4 },"Comp6":{ "value" : 5 },"Comp7":{ "value" : 6 },"Comp8":{ "value" : 7 } } ] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + let newEntities = try family.decodeMembers(from: jsonData, using: &jsonDecoder) + XCTAssertEqual(newEntities.count, 3) + XCTAssertEqual(family.count, 3) + } +} + +// MARK: - Components +final class Comp1: Component { + var value: Int + init(_ value: Int) { self.value = value } +} +extension Comp1: Equatable { + static func == (lhs: Comp1, rhs: Comp1) -> Bool { + lhs === rhs && lhs.value == rhs.value + } +} +extension Comp1: Codable { } + +final class Comp2: Component { + var value: Int + init(_ value: Int) { self.value = value } +} +extension Comp2: Equatable { + static func == (lhs: Comp2, rhs: Comp2) -> Bool { + lhs === rhs && lhs.value == rhs.value + } +} +extension Comp2: Codable { } + +final class Comp3: Component { + var value: Int + init(_ value: Int) { self.value = value } +} +extension Comp3: Equatable { + static func == (lhs: Comp3, rhs: Comp3) -> Bool { + lhs === rhs && lhs.value == rhs.value + } +} +extension Comp3: Codable { } + +final class Comp4: Component { + var value: Int + init(_ value: Int) { self.value = value } +} +extension Comp4: Equatable { + static func == (lhs: Comp4, rhs: Comp4) -> Bool { + lhs === rhs && lhs.value == rhs.value + } +} +extension Comp4: Codable { } + +final class Comp5: Component { + var value: Int + init(_ value: Int) { self.value = value } +} +extension Comp5: Equatable { + static func == (lhs: Comp5, rhs: Comp5) -> Bool { + lhs === rhs && lhs.value == rhs.value + } +} +extension Comp5: Codable { } + +final class Comp6: Component { + var value: Int + init(_ value: Int) { self.value = value } +} +extension Comp6: Equatable { + static func == (lhs: Comp6, rhs: Comp6) -> Bool { + lhs === rhs && lhs.value == rhs.value + } +} +extension Comp6: Codable { } + +final class Comp7: Component { + var value: Int + init(_ value: Int) { self.value = value } +} +extension Comp7: Equatable { + static func == (lhs: Comp7, rhs: Comp7) -> Bool { + lhs === rhs && lhs.value == rhs.value + } +} +extension Comp7: Codable { } + +final class Comp8: Component { + var value: Int + init(_ value: Int) { self.value = value } +} +extension Comp8: Equatable { + static func == (lhs: Comp8, rhs: Comp8) -> Bool { + lhs === rhs && lhs.value == rhs.value + } +} +extension Comp8: Codable { } diff --git a/Tests/FirebladeECSTests/XCTestManifests.swift b/Tests/FirebladeECSTests/XCTestManifests.swift index 14f13cf..cec97be 100644 --- a/Tests/FirebladeECSTests/XCTestManifests.swift +++ b/Tests/FirebladeECSTests/XCTestManifests.swift @@ -46,6 +46,118 @@ extension EntityTests { ] } +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), + ("testMemberCreation", testMemberCreation) + ] +} + +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), + ("testMemberCreation", testMemberCreation) + ] +} + +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), + ("testMemberCreation", testMemberCreation) + ] +} + +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), + ("testMemberCreation", testMemberCreation) + ] +} + +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), + ("testMemberCreation", testMemberCreation) + ] +} + +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), + ("testMemberCreation", testMemberCreation) + ] +} + +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), + ("testMemberCreation", testMemberCreation) + ] +} + +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), + ("testMemberCreation", testMemberCreation) + ] +} + extension FamilyCodingTests { // DO NOT MODIFY: This is autogenerated, use: // `swift test --generate-linuxmain` @@ -177,6 +289,14 @@ public func __allTests() -> [XCTestCaseEntry] { testCase(ComponentTests.__allTests__ComponentTests), testCase(EntityCreationTests.__allTests__EntityCreationTests), 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), From c960ed32e12a3904bcd50f52f74cae0ceb9e25eb Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Thu, 6 Aug 2020 10:34:01 +0200 Subject: [PATCH 19/21] Remove exclude --- Package.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Package.swift b/Package.swift index e7ac6b8..36f03a2 100644 --- a/Package.swift +++ b/Package.swift @@ -8,8 +8,7 @@ let package = Package( targets: ["FirebladeECS"]) ], targets: [ - .target(name: "FirebladeECS", - exclude: ["Stencils"]), + .target(name: "FirebladeECS"), .testTarget(name: "FirebladeECSTests", dependencies: ["FirebladeECS"]), .testTarget(name: "FirebladeECSPerformanceTests", From b662565a79c9ecac0b3437dccd4ca7ea58374cd2 Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Thu, 6 Aug 2020 10:49:27 +0200 Subject: [PATCH 20/21] Add family decoding failure test --- .../Generated/FamilyTests.generated.swift | 208 ++++++++++++++++++ .../Stencils/FamilyTests.stencil | 28 ++- Tests/FirebladeECSTests/XCTestManifests.swift | 8 + 3 files changed, 243 insertions(+), 1 deletion(-) diff --git a/Tests/FirebladeECSTests/Generated/FamilyTests.generated.swift b/Tests/FirebladeECSTests/Generated/FamilyTests.generated.swift index 10d8611..a00cad9 100644 --- a/Tests/FirebladeECSTests/Generated/FamilyTests.generated.swift +++ b/Tests/FirebladeECSTests/Generated/FamilyTests.generated.swift @@ -107,6 +107,32 @@ final class Family1Tests: XCTestCase { XCTAssertEqual(newEntities.count, 3) XCTAssertEqual(family.count, 3) } + + func testFamilyFailDecoding() { + let jsonString = """ + [{ "SomeOtherComp": { "someValue": "fail" } }] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requires: Comp1.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + XCTAssertThrowsError(try family.decodeMembers(from: jsonData, using: &jsonDecoder)) { error in + switch error { + case let decodingError as DecodingError: + switch decodingError { + case .keyNotFound: + break + default: + XCTFail("Wrong error provided \(error)") + } + default: + XCTFail("Wrong error provided \(error)") + } + } + } } // MARK: - Family 2 test case @@ -218,6 +244,32 @@ final class Family2Tests: XCTestCase { XCTAssertEqual(newEntities.count, 3) XCTAssertEqual(family.count, 3) } + + func testFamilyFailDecoding() { + let jsonString = """ + [{ "SomeOtherComp": { "someValue": "fail" } }] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + XCTAssertThrowsError(try family.decodeMembers(from: jsonData, using: &jsonDecoder)) { error in + switch error { + case let decodingError as DecodingError: + switch decodingError { + case .keyNotFound: + break + default: + XCTFail("Wrong error provided \(error)") + } + default: + XCTFail("Wrong error provided \(error)") + } + } + } } // MARK: - Family 3 test case @@ -335,6 +387,32 @@ final class Family3Tests: XCTestCase { XCTAssertEqual(newEntities.count, 3) XCTAssertEqual(family.count, 3) } + + func testFamilyFailDecoding() { + let jsonString = """ + [{ "SomeOtherComp": { "someValue": "fail" } }] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + XCTAssertThrowsError(try family.decodeMembers(from: jsonData, using: &jsonDecoder)) { error in + switch error { + case let decodingError as DecodingError: + switch decodingError { + case .keyNotFound: + break + default: + XCTFail("Wrong error provided \(error)") + } + default: + XCTFail("Wrong error provided \(error)") + } + } + } } // MARK: - Family 4 test case @@ -458,6 +536,32 @@ final class Family4Tests: XCTestCase { XCTAssertEqual(newEntities.count, 3) XCTAssertEqual(family.count, 3) } + + func testFamilyFailDecoding() { + let jsonString = """ + [{ "SomeOtherComp": { "someValue": "fail" } }] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + XCTAssertThrowsError(try family.decodeMembers(from: jsonData, using: &jsonDecoder)) { error in + switch error { + case let decodingError as DecodingError: + switch decodingError { + case .keyNotFound: + break + default: + XCTFail("Wrong error provided \(error)") + } + default: + XCTFail("Wrong error provided \(error)") + } + } + } } // MARK: - Family 5 test case @@ -587,6 +691,32 @@ final class Family5Tests: XCTestCase { XCTAssertEqual(newEntities.count, 3) XCTAssertEqual(family.count, 3) } + + func testFamilyFailDecoding() { + let jsonString = """ + [{ "SomeOtherComp": { "someValue": "fail" } }] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + XCTAssertThrowsError(try family.decodeMembers(from: jsonData, using: &jsonDecoder)) { error in + switch error { + case let decodingError as DecodingError: + switch decodingError { + case .keyNotFound: + break + default: + XCTFail("Wrong error provided \(error)") + } + default: + XCTFail("Wrong error provided \(error)") + } + } + } } // MARK: - Family 6 test case @@ -722,6 +852,32 @@ final class Family6Tests: XCTestCase { XCTAssertEqual(newEntities.count, 3) XCTAssertEqual(family.count, 3) } + + func testFamilyFailDecoding() { + let jsonString = """ + [{ "SomeOtherComp": { "someValue": "fail" } }] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + XCTAssertThrowsError(try family.decodeMembers(from: jsonData, using: &jsonDecoder)) { error in + switch error { + case let decodingError as DecodingError: + switch decodingError { + case .keyNotFound: + break + default: + XCTFail("Wrong error provided \(error)") + } + default: + XCTFail("Wrong error provided \(error)") + } + } + } } // MARK: - Family 7 test case @@ -863,6 +1019,32 @@ final class Family7Tests: XCTestCase { XCTAssertEqual(newEntities.count, 3) XCTAssertEqual(family.count, 3) } + + func testFamilyFailDecoding() { + let jsonString = """ + [{ "SomeOtherComp": { "someValue": "fail" } }] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + XCTAssertThrowsError(try family.decodeMembers(from: jsonData, using: &jsonDecoder)) { error in + switch error { + case let decodingError as DecodingError: + switch decodingError { + case .keyNotFound: + break + default: + XCTFail("Wrong error provided \(error)") + } + default: + XCTFail("Wrong error provided \(error)") + } + } + } } // MARK: - Family 8 test case @@ -1010,6 +1192,32 @@ final class Family8Tests: XCTestCase { XCTAssertEqual(newEntities.count, 3) XCTAssertEqual(family.count, 3) } + + func testFamilyFailDecoding() { + let jsonString = """ + [{ "SomeOtherComp": { "someValue": "fail" } }] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family(requiresAll: Comp1.self, Comp2.self, Comp3.self, Comp4.self, Comp5.self, Comp6.self, Comp7.self, Comp8.self) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + XCTAssertThrowsError(try family.decodeMembers(from: jsonData, using: &jsonDecoder)) { error in + switch error { + case let decodingError as DecodingError: + switch decodingError { + case .keyNotFound: + break + default: + XCTFail("Wrong error provided \(error)") + } + default: + XCTFail("Wrong error provided \(error)") + } + } + } } // MARK: - Components diff --git a/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil b/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil index 8c9a357..36b2e3c 100644 --- a/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil +++ b/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil @@ -92,7 +92,7 @@ final class Family{{ idx }}Tests: XCTestCase { XCTAssertEqual(family.count, 10_000) var idx: Int = 0 family.entityAndComponents.forEach { (entity, {{ CompsLowercased }}) in - XCTAssertEqual(entity.numComponents, {{ idx }}) + XCTAssertEqual(entity.numComponents, {{ idx }}) {% for comp in components %} XCTAssertEqual({{ comp|lowercase }}.value, {{ forloop.counter0 }}_000_000 + idx) XCTAssertEqual(entity[\{{ comp }}.self], {{ comp|lowercase }}) @@ -138,6 +138,32 @@ final class Family{{ idx }}Tests: XCTestCase { XCTAssertEqual(newEntities.count, 3) XCTAssertEqual(family.count, 3) } + + func testFamilyFailDecoding() { + let jsonString = """ + [{ "SomeOtherComp": { "someValue": "fail" } }] + """ + guard let jsonData = jsonString.data(using: .utf8) else { + XCTFail("Failed to read data from json string \(jsonString.count)") + return + } + let family = nexus.family({% if components.count == 1 %}requires{% else %}requiresAll{%endif%}: {{ CompsSelf }}) + XCTAssertTrue(family.isEmpty) + var jsonDecoder = JSONDecoder() + XCTAssertThrowsError(try family.decodeMembers(from: jsonData, using: &jsonDecoder)) { error in + switch error { + case let decodingError as DecodingError: + switch decodingError { + case .keyNotFound: + break + default: + XCTFail("Wrong error provided \(error)") + } + default: + XCTFail("Wrong error provided \(error)") + } + } + } } {% endfor %} diff --git a/Tests/FirebladeECSTests/XCTestManifests.swift b/Tests/FirebladeECSTests/XCTestManifests.swift index cec97be..66c786a 100644 --- a/Tests/FirebladeECSTests/XCTestManifests.swift +++ b/Tests/FirebladeECSTests/XCTestManifests.swift @@ -56,6 +56,7 @@ extension Family1Tests { ("testEntityIteration", testEntityIteration), ("testFamilyDecoding", testFamilyDecoding), ("testFamilyEncoding", testFamilyEncoding), + ("testFamilyFailDecoding", testFamilyFailDecoding), ("testMemberCreation", testMemberCreation) ] } @@ -70,6 +71,7 @@ extension Family2Tests { ("testEntityIteration", testEntityIteration), ("testFamilyDecoding", testFamilyDecoding), ("testFamilyEncoding", testFamilyEncoding), + ("testFamilyFailDecoding", testFamilyFailDecoding), ("testMemberCreation", testMemberCreation) ] } @@ -84,6 +86,7 @@ extension Family3Tests { ("testEntityIteration", testEntityIteration), ("testFamilyDecoding", testFamilyDecoding), ("testFamilyEncoding", testFamilyEncoding), + ("testFamilyFailDecoding", testFamilyFailDecoding), ("testMemberCreation", testMemberCreation) ] } @@ -98,6 +101,7 @@ extension Family4Tests { ("testEntityIteration", testEntityIteration), ("testFamilyDecoding", testFamilyDecoding), ("testFamilyEncoding", testFamilyEncoding), + ("testFamilyFailDecoding", testFamilyFailDecoding), ("testMemberCreation", testMemberCreation) ] } @@ -112,6 +116,7 @@ extension Family5Tests { ("testEntityIteration", testEntityIteration), ("testFamilyDecoding", testFamilyDecoding), ("testFamilyEncoding", testFamilyEncoding), + ("testFamilyFailDecoding", testFamilyFailDecoding), ("testMemberCreation", testMemberCreation) ] } @@ -126,6 +131,7 @@ extension Family6Tests { ("testEntityIteration", testEntityIteration), ("testFamilyDecoding", testFamilyDecoding), ("testFamilyEncoding", testFamilyEncoding), + ("testFamilyFailDecoding", testFamilyFailDecoding), ("testMemberCreation", testMemberCreation) ] } @@ -140,6 +146,7 @@ extension Family7Tests { ("testEntityIteration", testEntityIteration), ("testFamilyDecoding", testFamilyDecoding), ("testFamilyEncoding", testFamilyEncoding), + ("testFamilyFailDecoding", testFamilyFailDecoding), ("testMemberCreation", testMemberCreation) ] } @@ -154,6 +161,7 @@ extension Family8Tests { ("testEntityIteration", testEntityIteration), ("testFamilyDecoding", testFamilyDecoding), ("testFamilyEncoding", testFamilyEncoding), + ("testFamilyFailDecoding", testFamilyFailDecoding), ("testMemberCreation", testMemberCreation) ] } From 3881a2c66ab46fcdb0bdc4098a4d2b279db2cf5b Mon Sep 17 00:00:00 2001 From: Christian Treffs Date: Thu, 6 Aug 2020 10:52:52 +0200 Subject: [PATCH 21/21] Cleanups --- Tests/FirebladeECSTests/Stencils/FamilyTests.stencil | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil b/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil index 36b2e3c..5e66d31 100644 --- a/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil +++ b/Tests/FirebladeECSTests/Stencils/FamilyTests.stencil @@ -167,7 +167,6 @@ final class Family{{ idx }}Tests: XCTestCase { } {% endfor %} - // MARK: - Components {% for idx in 1...8 %} final class Comp{{ idx }}: Component { @@ -178,7 +177,7 @@ extension Comp{{ idx }}: Equatable { static func == (lhs: Comp{{ idx }}, rhs: Comp{{ idx }}) -> Bool { lhs === rhs && lhs.value == rhs.value } - } +} extension Comp{{ idx }}: Codable { } {% endfor %} \ No newline at end of file