The combination EmulatedBitIntegers.jl + PackedStructs.jl seems somewhat related to the type PackedVector from SmallCollections.jl. (Disclaimer: I’m the author.) For example
julia> v = PackedVector{UInt16,5,Int8}([1,9])
2-element PackedVector{UInt16, 5, Int8}:
1
9
defines a vector with 5-bit integers that are packed into an UInt16 (hence with maximal length 3) and appear to the outside as Int8. Besides vector operations like
julia> Int8(3) * v
2-element PackedVector{UInt16, 5, Int8}:
3
-5
(note the overflow) there are functions like push, filter or findfirst.
Maybe one can combine PackedVector with EmulatedBitIntegers.jl to declare an honest element type Int5 instead of the fake Int8.