collidingEntities = filteredSystem("collidingEntitites", {
    position = T.XyPair,
    size = T.XyPair,
    canCollideWith = T.BitMask,
    isSolid = Maybe(T.bool),
})

local function intersects(rect, rectOther)
    local left = rect.position.x
    local right = rect.position.x + rect.size.x
    local top = rect.position.y
    local bottom = rect.position.y + rect.size.y

    local leftOther = rectOther.position.x
    local rightOther = rectOther.position.x + rectOther.size.x
    local topOther = rectOther.position.y
    local bottomOther = rectOther.position.y + rectOther.size.y

    return leftOther < right and left < rightOther and topOther < bottom and top < bottomOther
end

filteredSystem(
    "collisionDetection",
    { position = T.XyPair, size = T.XyPair, canBeCollidedBy = T.BitMask, isSolid = Maybe(T.bool) },
-- Here, the entity, e, refers to some entity that a moving object may be colliding *into*
    function(e, _, system)
        for _, collider in pairs(collidingEntities.entities) do
            if
            (e ~= collider)
                and collider.canCollideWith
                and e.canBeCollidedBy
                and bit.band(collider.canCollideWith, e.canBeCollidedBy) ~= 0
            then
                if intersects(e, collider) then
                    system.world:addEntity({ collisionBetween = { e, collider } })
                end
            end
        end
    end
)