From 8819e10d9eebb2ff09c82dc6dd6f0e3e4aa13ab7 Mon Sep 17 00:00:00 2001 From: Matei Adriel Date: Sun, 4 Jun 2023 15:21:21 +0200 Subject: [PATCH] Added ecs --- ecs/.gitignore | 10 ++ ecs/package.json | 8 ++ ecs/packages.dhall | 104 ++++++++++++++++++ ecs/pnpm-lock.yaml | 185 ++++++++++++++++++++++++++++++++ ecs/spago.dhall | 26 +++++ ecs/src/Main.purs | 10 ++ ecs/src/Types.js | 43 ++++++++ ecs/src/Types.purs | 227 ++++++++++++++++++++++++++++++++++++++++ ecs/src/Utils/Keys.purs | 40 +++++++ ecs/test/Main.purs | 11 ++ ecs/tsconfig.json | 101 ++++++++++++++++++ 11 files changed, 765 insertions(+) create mode 100644 ecs/.gitignore create mode 100644 ecs/package.json create mode 100644 ecs/packages.dhall create mode 100644 ecs/pnpm-lock.yaml create mode 100644 ecs/spago.dhall create mode 100644 ecs/src/Main.purs create mode 100644 ecs/src/Types.js create mode 100644 ecs/src/Types.purs create mode 100644 ecs/src/Utils/Keys.purs create mode 100644 ecs/test/Main.purs create mode 100644 ecs/tsconfig.json diff --git a/ecs/.gitignore b/ecs/.gitignore new file mode 100644 index 0000000..30efe19 --- /dev/null +++ b/ecs/.gitignore @@ -0,0 +1,10 @@ +/bower_components/ +/node_modules/ +/.pulp-cache/ +/output/ +/generated-docs/ +/.psc-package/ +/.psc* +/.purs* +/.psa* +/.spago diff --git a/ecs/package.json b/ecs/package.json new file mode 100644 index 0000000..47c6fb3 --- /dev/null +++ b/ecs/package.json @@ -0,0 +1,8 @@ +{ + "dependencies": { + "@thi.ng/ecs": "^0.7.2" + }, + "devDependencies": { + "typescript": "^4.5.2" + } +} diff --git a/ecs/packages.dhall b/ecs/packages.dhall new file mode 100644 index 0000000..9cbf06a --- /dev/null +++ b/ecs/packages.dhall @@ -0,0 +1,104 @@ +{- +Welcome to your new Dhall package-set! + +Below are instructions for how to edit this file for most use +cases, so that you don't need to know Dhall to use it. + +## Use Cases + +Most will want to do one or both of these options: +1. Override/Patch a package's dependency +2. Add a package not already in the default package set + +This file will continue to work whether you use one or both options. +Instructions for each option are explained below. + +### Overriding/Patching a package + +Purpose: +- Change a package's dependency to a newer/older release than the + default package set's release +- Use your own modified version of some dependency that may + include new API, changed API, removed API by + using your custom git repo of the library rather than + the package set's repo + +Syntax: +where `entityName` is one of the following: +- dependencies +- repo +- version +------------------------------- +let upstream = -- +in upstream + with packageName.entityName = "new value" +------------------------------- + +Example: +------------------------------- +let upstream = -- +in upstream + with halogen.version = "master" + with halogen.repo = "https://example.com/path/to/git/repo.git" + + with halogen-vdom.version = "v4.0.0" + with halogen-vdom.dependencies = [ "extra-dependency" ] # halogen-vdom.dependencies +------------------------------- + +### Additions + +Purpose: +- Add packages that aren't already included in the default package set + +Syntax: +where `` is: +- a tag (i.e. "v4.0.0") +- a branch (i.e. "master") +- commit hash (i.e. "701f3e44aafb1a6459281714858fadf2c4c2a977") +------------------------------- +let upstream = -- +in upstream + with new-package-name = + { dependencies = + [ "dependency1" + , "dependency2" + ] + , repo = + "https://example.com/path/to/git/repo.git" + , version = + "" + } +------------------------------- + +Example: +------------------------------- +let upstream = -- +in upstream + with benchotron = + { dependencies = + [ "arrays" + , "exists" + , "profunctor" + , "strings" + , "quickcheck" + , "lcg" + , "transformers" + , "foldable-traversable" + , "exceptions" + , "node-fs" + , "node-buffer" + , "node-readline" + , "datetime" + , "now" + ] + , repo = + "https://github.com/hdgarrood/purescript-benchotron.git" + , version = + "v7.0.0" + } +------------------------------- +-} +let upstream = + https://github.com/purescript/package-sets/releases/download/psc-0.14.5-20211116/packages.dhall sha256:7ba810597a275e43c83411d2ab0d4b3c54d0b551436f4b1632e9ff3eb62e327a + +in upstream diff --git a/ecs/pnpm-lock.yaml b/ecs/pnpm-lock.yaml new file mode 100644 index 0000000..66a0f24 --- /dev/null +++ b/ecs/pnpm-lock.yaml @@ -0,0 +1,185 @@ +lockfileVersion: 5.3 + +specifiers: + '@thi.ng/ecs': ^0.7.2 + typescript: ^4.5.2 + +dependencies: + '@thi.ng/ecs': 0.7.2 + +devDependencies: + typescript: 4.5.2 + +packages: + + /@thi.ng/api/8.3.2: + resolution: {integrity: sha512-sZBbrBtSzXQlCcyxkFwOysvvU9bqcsEQJCqSpxtSmju16c1RjDGLQ/hdv755QRBkNywKykypNBwutUtpaejUfA==} + engines: {node: '>=12.7'} + dev: false + + /@thi.ng/arrays/2.1.2: + resolution: {integrity: sha512-QS0uJFln7xeCyJcDtqjXdov1ta7PMSYjrb17AjjUvSfvPUkLArCJMVTJBl4k9QrFirp8N3Blc1e8xZJgeK9lrg==} + engines: {node: '>=12.7'} + dependencies: + '@thi.ng/api': 8.3.2 + '@thi.ng/checks': 3.1.2 + '@thi.ng/compare': 2.1.2 + '@thi.ng/equiv': 2.1.2 + '@thi.ng/errors': 2.1.2 + '@thi.ng/random': 3.2.2 + dev: false + + /@thi.ng/associative/6.1.2: + resolution: {integrity: sha512-Bf1gncNPmAxe6j4cRMhi0nj+2qLUVQznA2VA5U+pqMoI42mOf8zvC28U0GpUzJ+9h53Sv6+P11oDHEQs6qsleA==} + engines: {node: '>=12.7'} + dependencies: + '@thi.ng/api': 8.3.2 + '@thi.ng/arrays': 2.1.2 + '@thi.ng/binary': 3.1.2 + '@thi.ng/checks': 3.1.2 + '@thi.ng/compare': 2.1.2 + '@thi.ng/dcons': 3.1.2 + '@thi.ng/equiv': 2.1.2 + '@thi.ng/errors': 2.1.2 + '@thi.ng/transducers': 8.1.2 + tslib: 2.3.1 + dev: false + + /@thi.ng/binary/3.1.2: + resolution: {integrity: sha512-7PajvPvxT8iG0c4xPg9v/x7tiTWESz/VQMIHvX3pT9mO0wqKJoc4jWUFXCnWqHItnBwNsuEvRPI6I8KjqPnXIg==} + engines: {node: '>=12.7'} + dependencies: + '@thi.ng/api': 8.3.2 + dev: false + + /@thi.ng/checks/3.1.2: + resolution: {integrity: sha512-DyypenoE0bh7hpeBDihHaPqxJmUe2AtQI9dcyGwkizjmaanBSHzJlfckkz46CYoDcq51DnJWn23+GLVJ3qFYhA==} + engines: {node: '>=12.7'} + dependencies: + tslib: 2.3.1 + dev: false + + /@thi.ng/compare/2.1.2: + resolution: {integrity: sha512-0BmxdiG9ybDlzA03dCt6fisjhx9eyP81ODD9JNHT+rNuizt6SApzywjvr+J2GT5HG76SzaSQE8WpvGbScwAS8Q==} + engines: {node: '>=12.7'} + dependencies: + '@thi.ng/api': 8.3.2 + dev: false + + /@thi.ng/compose/2.1.2: + resolution: {integrity: sha512-z0d6G2y3vYlR5IJRn0ehTSyk+2bLhQwnQXxr7EBADq7qlARu0Wco0WIkO2y6FmLDF2M4NKvho8F9K1iqt1jXyQ==} + engines: {node: '>=12.7'} + dependencies: + '@thi.ng/api': 8.3.2 + '@thi.ng/errors': 2.1.2 + dev: false + + /@thi.ng/dcons/3.1.2: + resolution: {integrity: sha512-RPxxa0DCbmZ4Y9+ffP6WRv6zbwcH14gthxhDycAnpplryu4vgIjNeOV2XW80S2qAINN2RDkC52jO7iA30HzDIw==} + engines: {node: '>=12.7'} + dependencies: + '@thi.ng/api': 8.3.2 + '@thi.ng/checks': 3.1.2 + '@thi.ng/compare': 2.1.2 + '@thi.ng/equiv': 2.1.2 + '@thi.ng/errors': 2.1.2 + '@thi.ng/random': 3.2.2 + '@thi.ng/transducers': 8.1.2 + dev: false + + /@thi.ng/ecs/0.7.2: + resolution: {integrity: sha512-HeEIif+gJm57sdlnWURUrUi/kKWUfc1P/dGk6CNuo4Sg1fo8XPCWR5y2dSLN+dsUyMlw9LAJWR/rvhDOwK//6w==} + engines: {node: '>=12.7'} + dependencies: + '@thi.ng/api': 8.3.2 + '@thi.ng/associative': 6.1.2 + '@thi.ng/binary': 3.1.2 + '@thi.ng/checks': 3.1.2 + '@thi.ng/dcons': 3.1.2 + '@thi.ng/errors': 2.1.2 + '@thi.ng/idgen': 2.1.2 + '@thi.ng/logger': 1.1.2 + '@thi.ng/malloc': 6.1.2 + '@thi.ng/transducers': 8.1.2 + tslib: 2.3.1 + dev: false + + /@thi.ng/equiv/2.1.2: + resolution: {integrity: sha512-S0QZmWXIO5d/TQSLsyFLYT3/j9nKRuJMUEJYz8seFnQQ9ydrAjV4o5pIHbXiWnjllHAWYa/iN6LJ8xuV8nXxag==} + engines: {node: '>=12.7'} + dev: false + + /@thi.ng/errors/2.1.2: + resolution: {integrity: sha512-3XdabkDNqrL76HVlt3q01zqMRLnSB8FFjJchiYWT/RVkAI2OBogE+eBy4KhYc0mvssYPfdnP9ikjDrV1CC2rVg==} + engines: {node: '>=12.7'} + dev: false + + /@thi.ng/hex/2.1.2: + resolution: {integrity: sha512-JFUApXIn7HWFYEZMQLtf9rZ1aeXFFI8ggdJrA45PzVC0kl73J8yeRHlXn3kjV7spd7jk7oatdEm4JnvadbT4EQ==} + engines: {node: '>=12.7'} + dev: false + + /@thi.ng/idgen/2.1.2: + resolution: {integrity: sha512-15jngVT0kdlrWeTfeXnLBTN8RZW7nCrs2r8c2dj3OGm8cbQDwnd9LxwlYMhu37flMTG55cFiVbiftTK6TEvGWA==} + engines: {node: '>=12.7'} + dependencies: + '@thi.ng/api': 8.3.2 + '@thi.ng/errors': 2.1.2 + tslib: 2.3.1 + dev: false + + /@thi.ng/logger/1.1.2: + resolution: {integrity: sha512-zMUAkz7TJ6maTxerWiimGdoCsKR+v1kCyTkRxT1ii0dtTkvhtjhSPpnFAIMM/S4+7PdKxpiTqAl3oFNTt+EN7A==} + engines: {node: '>=12.7'} + dev: false + + /@thi.ng/malloc/6.1.2: + resolution: {integrity: sha512-PPAJmN17CS+HhmKCwFrgXYNXsSSs5zRZJdE5CsCqvvKHnKg+YsAoHFudkmmpIilLdCzFkyZK6gHBT+63jD/xbw==} + engines: {node: '>=12.7'} + dependencies: + '@thi.ng/api': 8.3.2 + '@thi.ng/binary': 3.1.2 + '@thi.ng/checks': 3.1.2 + '@thi.ng/errors': 2.1.2 + dev: false + + /@thi.ng/math/5.1.2: + resolution: {integrity: sha512-iOzs+cy19sxlOxk6OW5xDx5+rsvbXahqOf9Y323zs14VPS/I7rJl9SMY2F5MDbxZf65m3si6nolzOVW0a52C4Q==} + engines: {node: '>=12.7'} + dependencies: + '@thi.ng/api': 8.3.2 + dev: false + + /@thi.ng/random/3.2.2: + resolution: {integrity: sha512-QJD+F2kXfFyTI//EEVnVHP4XdeBhm9tlxavaAZizfIRKwWWxhrAHdk8BDPnN3nQe74Ana6UZy2NMrb3nb0A/gQ==} + engines: {node: '>=12.7'} + dependencies: + '@thi.ng/api': 8.3.2 + '@thi.ng/checks': 3.1.2 + '@thi.ng/errors': 2.1.2 + '@thi.ng/hex': 2.1.2 + dev: false + + /@thi.ng/transducers/8.1.2: + resolution: {integrity: sha512-nMZNrMA8yJfvFpVtIYF31bBHsGJGadci+I3/VqUBneBfWM2aFbJcOjYAyLq7Xe15RBTx9eGfBikPGTcvz5ILfA==} + engines: {node: '>=12.7'} + dependencies: + '@thi.ng/api': 8.3.2 + '@thi.ng/arrays': 2.1.2 + '@thi.ng/checks': 3.1.2 + '@thi.ng/compare': 2.1.2 + '@thi.ng/compose': 2.1.2 + '@thi.ng/errors': 2.1.2 + '@thi.ng/math': 5.1.2 + '@thi.ng/random': 3.2.2 + dev: false + + /tslib/2.3.1: + resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} + dev: false + + /typescript/4.5.2: + resolution: {integrity: sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==} + engines: {node: '>=4.2.0'} + hasBin: true + dev: true diff --git a/ecs/spago.dhall b/ecs/spago.dhall new file mode 100644 index 0000000..f86e865 --- /dev/null +++ b/ecs/spago.dhall @@ -0,0 +1,26 @@ +{- +Welcome to a Spago project! +You can edit this file as you like. + +Need help? See the following resources: +- Spago documentation: https://github.com/purescript/spago +- Dhall language tour: https://docs.dhall-lang.org/tutorials/Language-Tour.html + +When creating a new Spago project, you can use +`spago init --no-comments` or `spago init -C` +to generate this file without the comments in this block. +-} +{ name = "my-project" +, dependencies = + [ "arraybuffer-types" + , "console" + , "effect" + , "heterogeneous" + , "lazy" + , "prelude" + , "psci-support" + , "undefined-is-not-a-problem" + ] +, packages = ./packages.dhall +, sources = [ "src/**/*.purs", "test/**/*.purs" ] +} diff --git a/ecs/src/Main.purs b/ecs/src/Main.purs new file mode 100644 index 0000000..5c18dca --- /dev/null +++ b/ecs/src/Main.purs @@ -0,0 +1,10 @@ +module Main where + +import Prelude + +import Effect (Effect) +import Effect.Console (log) + +main :: Effect Unit +main = do + log "🍝" diff --git a/ecs/src/Types.js b/ecs/src/Types.js new file mode 100644 index 0000000..bd46a40 --- /dev/null +++ b/ecs/src/Types.js @@ -0,0 +1,43 @@ +// @ts-check +const ecs = require("@thi.ng/ecs"); + +exports.makeEcs = + ({ size, components }) => + () => { + const thisEcs = new ecs.ECS({ + capacity: size, + }); + + for (const key in components) { + const component = { id: key }; + Object.assign(component, components[key]); + thisEcs.defComponent(component); + } + + return ecs; + }; + +exports.unsafeCreateEntity = (components, /** @type {ecs.ECS} */ ecs) => { + return ecs.defEntity(components); +}; + +exports.deleteEntity = + (/** @type {number} */ id) => (/** @type {ecs.ECS} */ ecs) => () => { + return ecs.deleteID(id); + }; + +exports.unsafeCreateGroup = ( + components, + owned, + opts, + /** @type {ecs.ECS} */ ecs +) => { + return ecs.defGroup(components, owned, opts); +}; + +exports.unsafeGetComponentManager = ( + /** @type {string} */ name, + /** @type {ecs.ECS} */ ecs +) => { + return ecs.components.get(name); +}; diff --git a/ecs/src/Types.purs b/ecs/src/Types.purs new file mode 100644 index 0000000..d40805e --- /dev/null +++ b/ecs/src/Types.purs @@ -0,0 +1,227 @@ +module Thing.Ecs.Types + ( Cache + , ComponentManager + , ComponentSet + , ComponentSpec + , Ecs + , EcsSpec + , EntityId + , Group + , GroupSpec + , MakeComponentSet + , MemMappedComponent + , MemPool + , OpaqueComponentManager + , SelectGroupComponents + , createEntity + , createGroup + , deleteEntity + , makeComponentSet + , makeEcs + , unsafeCreateEntity + , unsafeCreateGroup + ) where + +import Prelude + +import Data.ArrayBuffer.Types (ArrayBuffer) +import Data.List (List) +import Data.List as List +import Data.Symbol (class IsSymbol, reflectSymbol) +import Data.Undefined.NoProblem (Opt) +import Effect (Effect) +import Effect.Uncurried (EffectFn2, EffectFn4, runEffectFn2, runEffectFn4) +import Heterogeneous.Folding (class FoldingWithIndex, class HFoldlWithIndex, hfoldlWithIndex) +import Heterogeneous.Mapping (class HMap, class Mapping) +import Prim.Row as Row +import Prim.RowList as RL +import Type.Data.RowList (RLProxy(..)) +import Type.Proxy (Proxy) +import Unsafe.Coerce (unsafeCoerce) + +-- | The entity component system is the core of the library. +-- | This is an opaque type, used by the different helpers provided by this library. +data Ecs :: Row Type -> Type +data Ecs components + +-- | A group is what keeps track of the intersection of multiple component managers +data Group :: Row Type -> Type +data Group components + +-- | A component manager is the class which manages the lifetime of a particular component +data ComponentManager :: Symbol -> Type -> Type +data ComponentManager name component + +data OpaqueComponentManager + +-- | Unique id identifying an entity +newtype EntityId :: Type +newtype EntityId = EntityId Int + +---------- Configuration options +-- | Opaque type which represents instances of classes which implement [ICache](https://docs.thi.ng/umbrella/ecs/interfaces/ICache.html) +data Cache + +-- | A memory mapped component should lead to more efficient iteration speed (?) +-- | and somewhat easy interop with the gpu +type MemMappedComponent = + { buffer :: Opt ArrayBuffer + , byteOffset :: Opt Int + , size :: Opt Int + , stride :: Opt Int + , cache :: Opt Cache + , type :: String -- TODO: fix this + } + +-- | An individual component spec specifies how a manager stores it's components +data ComponentSpec :: forall k. k -> Type +data ComponentSpec a + -- | An object component manager can store any javascript value. Useful when the size of the data is not constant + = ObjectComponent + + | MemMappedComponent MemMappedComponent + +-- | A component set is just a set of configurations +-- | for the components specified by the given row type. +data ComponentSet :: Row Type -> Type +data ComponentSet components + +-- | Opaque type which represents classes implementing [IMemPoolArray](https://docs.thi.ng/umbrella/malloc/interfaces/imempoolarray.html) +data MemPool + +-- TODO: add custom object pool setting +-- | The config required to build an ecs +type EcsSpec components = + { + -- | The maximum amount of entities in the system at one point in time + size :: Int + + -- | Optional custom implementation of entity allocation / deallocation + , pool :: Opt MemPool + + -- | Configuration for all components in the entity component system + , components :: ComponentSet components + } + +-- | Options for creating a group +type GroupSpec = + { id :: Opt String + , cache :: Opt Cache + } + +---------- Component set creation +-- | Typelevel tag for the operation of creating component specs. +-- | Internal to this module. Exporting can lead to unsafe code. +data MakeComponentSet + +-- | Instance used to compute the record of component specs at the typelevel +instance Mapping MakeComponentSet n (ComponentSpec n) where + mapping = unsafeCoerce + +-- | Dummy function to remove typeclass constrains from a set of component specs +makeComponentSet + :: forall components specs + . HMap MakeComponentSet (Record components) (Record specs) + => Record specs + -> ComponentSet components +makeComponentSet = unsafeCoerce + +---------- Helpers +createEntity + :: forall components provided remaining + . Row.Union provided remaining components + => Record provided + -> Ecs components + -> Effect EntityId +createEntity = runEffectFn2 unsafeCreateEntity + +---------- Gruop creation +createGroup + :: forall components group remaining owned remaining' grl orl + . Row.Union group remaining components + => Row.Union owned remaining' components + => RL.RowToList owned orl + => RL.RowToList group grl + => HFoldlWithIndex SelectGroupComponents + (Ecs components -> List OpaqueComponentManager) + (RLProxy grl) + (Ecs components -> List OpaqueComponentManager) + => HFoldlWithIndex SelectGroupComponents + (Ecs components -> List OpaqueComponentManager) + (RLProxy orl) + (Ecs components -> List OpaqueComponentManager) + => Proxy group + -> Proxy owned + -> GroupSpec + -> Ecs components + -> Effect (Group remaining) +createGroup _ _ options ecs = runEffectFn4 unsafeCreateGroup + ( List.toUnfoldable $ hfoldlWithIndex + SelectGroupComponents + (const List.Nil :: Ecs components -> List OpaqueComponentManager) + _selected + ecs + ) + + ( List.toUnfoldable $ hfoldlWithIndex + SelectGroupComponents + (const List.Nil :: Ecs components -> List OpaqueComponentManager) + _owned + ecs + ) + options + ecs + where + _owned :: RLProxy orl + _owned = RLProxy + + _selected :: RLProxy grl + _selected = RLProxy + +data SelectGroupComponents = SelectGroupComponents + +instance + ( IsSymbol key + ) => + FoldingWithIndex SelectGroupComponents + (Proxy key) + (Ecs components -> List OpaqueComponentManager) + (Proxy ty) + (Ecs components -> List OpaqueComponentManager) + where + foldingWithIndex _ key previous _ ecs = List.Cons + (unsafeGetComponentManager name ecs) + (previous ecs) + where + name = reflectSymbol key + +---------- Foreign imports +-- | Unsafe version of makeEcs +foreign import makeEcs + :: forall result components + . EcsSpec components + -> (Ecs components -> result) + -> Effect result + +-- | Foreign, unsafe way of adding an entity to an ecs +foreign import unsafeCreateEntity + :: forall a b + . EffectFn2 + (Record a) + (Ecs b) + EntityId + +-- | Unsafe version of createGroup +foreign import unsafeCreateGroup + :: forall a b + . EffectFn4 + (Array OpaqueComponentManager) + (Array OpaqueComponentManager) + GroupSpec + (Ecs a) + (Group b) + +-- | Deletes an entity from the system +foreign import deleteEntity :: forall components. EntityId -> Ecs components -> Effect Boolean + +foreign import unsafeGetComponentManager :: forall components. String -> Ecs components -> OpaqueComponentManager \ No newline at end of file diff --git a/ecs/src/Utils/Keys.purs b/ecs/src/Utils/Keys.purs new file mode 100644 index 0000000..b47059e --- /dev/null +++ b/ecs/src/Utils/Keys.purs @@ -0,0 +1,40 @@ +-- | Modified version of the code from [record-extra](https://github.com/justinwoo/purescript-record-extra/blob/v4.0.0/src/Record/Extra.purs#L123-L127) +-- | I did not like how that lib used lists, so I modified it to output to an (initially) mutable array +module Thing.Ecs.Utils.Keys (keys, class Keys, keysImpl) where + +import Prelude + +import Control.Monad.ST (ST) +import Data.Array.ST (STArray) +import Data.Array.ST as STArray +import Data.Symbol (class IsSymbol, reflectSymbol) +import Prim.RowList as RL +import Type.Proxy (Proxy(..)) + +-- | Typeclass jk +class Keys (xs :: RL.RowList Type) where + keysImpl :: forall r. Proxy xs -> ST r (STArray r String) + +instance Keys RL.Nil where + keysImpl _ = STArray.empty + +instance + ( IsSymbol name + , Keys tail + ) => + Keys (RL.Cons name ty tail) where + keysImpl _ = do + rest <- keysImpl (Proxy :: _ tail) + _ <- STArray.push first rest + pure rest + where + first = reflectSymbol (Proxy :: _ name) + +-- | Extract a value level array of the keys of a row +keys + :: forall g row rl + . RL.RowToList row rl + => Keys rl + => g row -- this will work for any type with the row as a param! + -> Array String +keys _ = STArray.run (keysImpl (Proxy :: _ rl)) \ No newline at end of file diff --git a/ecs/test/Main.purs b/ecs/test/Main.purs new file mode 100644 index 0000000..f91f98c --- /dev/null +++ b/ecs/test/Main.purs @@ -0,0 +1,11 @@ +module Test.Main where + +import Prelude + +import Effect (Effect) +import Effect.Class.Console (log) + +main :: Effect Unit +main = do + log "🍝" + log "You should add some tests." diff --git a/ecs/tsconfig.json b/ecs/tsconfig.json new file mode 100644 index 0000000..0321886 --- /dev/null +++ b/ecs/tsconfig.json @@ -0,0 +1,101 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig.json to read more about this file */ + + /* Projects */ + // "incremental": true, /* Enable incremental compilation */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./", /* Specify the folder for .tsbuildinfo incremental compilation files. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h' */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using `jsx: react-jsx*`.` */ + // "reactNamespace": "", /* Specify the object invoked for `createElement`. This only applies when targeting `react` JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "node" /* Specify how TypeScript looks up a file from a given module specifier. */, + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like `./node_modules/@types`. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "resolveJsonModule": true, /* Enable importing .json files */ + // "noResolve": true, /* Disallow `import`s, `require`s or ``s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the `checkJS` option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from `node_modules`. Only applicable with `allowJs`. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If `declaration` is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have `@internal` in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like `__extends` in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing `const enum` declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + "isolatedModules": true /* Ensure that each file can be safely transpiled without relying on other imports. */, + "allowSyntheticDefaultImports": true /* Allow 'import x from y' when a module doesn't have a default export. */, + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables `allowSyntheticDefaultImports` for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied `any` type.. */ + // "strictNullChecks": true, /* When type checking, take into account `null` and `undefined`. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for `bind`, `call`, and `apply` methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when `this` is given the type `any`. */ + // "useUnknownInCatchVariables": true, /* Type catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when a local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +}