Hi all!
I have an ECS (entity component system) API and try to make type-stable use of tuples of types. Currently, I have it working well with VarArgs, for example:
pos, vel = get_components(world, entity, Position, Velocity)
However, I would prefer a tuple for the types, like this:
pos, vel = get_components(world, entity, (Position, Velocity))
Unfortunately, I am not able to get this working in a type-stable way.
My current working var-args approach looke like this:
unction get_components(world::World{CS,CT,N}, entity::Entity, comp_types::Type...) where {CS<:Tuple,CT<:Tuple,N}
if !is_alive(world, entity)
error("can't get components of a dead entity")
end
return _get_components(world, entity, Val{Tuple{comp_types...}}())
end
@generated function _get_components(world::World{CS,CT,N}, entity::Entity, ::Val{TS}) where {CS<:Tuple,CT<:Tuple,N,TS<:Tuple}
types = TS.parameters
if length(types) == 0
return :(())
end
exprs = Expr[]
push!(exprs, :(idx = world._entities[entity._id]))
for i in 1:length(types)
T = types[i]
stor_sym = Symbol("stor", i)
col_sym = Symbol("col", i)
val_sym = Symbol("v", i)
push!(exprs, :(
$(stor_sym) = _get_storage(world, Val{$(QuoteNode(T))}())
))
push!(exprs, :(
$(col_sym) = $(stor_sym).data[idx.archetype]
))
push!(exprs, :(
$(val_sym) = $(col_sym)._data[idx.row]
))
end
vals = [:($(Symbol("v", i))) for i in 1:length(types)]
push!(exprs, Expr(:return, Expr(:tuple, vals...)))
return quote
@inbounds begin
$(Expr(:block, exprs...))
end
end
end
I found two ways to use tuples in the API, but both are extemely slow due to type instability:
function get_components(world::World{CS,CT,N}, entity::Entity, comp_types::Tuple{Vararg{Type}}) where {CS<:Tuple,CT<:Tuple,N}
if !is_alive(world, entity)
error("can't get components of a dead entity")
end
return _get_components(world, entity, Val{Tuple{comp_types...}}())
end
@generated function _get_components(world::World{CS,CT,N}, entity::Entity, ::Val{TS}) where {CS<:Tuple,CT<:Tuple,N,TS<:Tuple}
function get_components(world::World{CS,CT,N}, entity::Entity, comp_types::Tuple{Vararg{Type}}) where {CS<:Tuple,CT<:Tuple,N}
if !is_alive(world, entity)
error("can't get components of a dead entity")
end
return _get_components(world, entity, Tuple{comp_types...})
end
@generated function _get_components(world::World{CS,CT,N}, entity::Entity, ::Type{TS}) where {CS<:Tuple,CT<:Tuple,N,TS<:Tuple}
So is there any way to properly convert my (Position, Velocity) to Tuple{Position, Velocity} (I guess) in a type-stable way?
Thank you in advance!