diff --git a/src/BitFlags.jl b/src/BitFlags.jl index 622b9e9..2eec7f3 100644 --- a/src/BitFlags.jl +++ b/src/BitFlags.jl @@ -50,7 +50,7 @@ function Base.print(io::IO, x::T) where T<:BitFlag multi = (haszero(T) ? !iszero(xi) : true) && !compact && !ispow2(xi) first = true sep = compact ? "|" : " | " - for (i, sym) in Iterators.reverse(namemap(T)) + for (sym, i) in Iterators.reverse(pairs(namemap(T))) if (first && iszero(i) && iszero(xi)) || !iszero(xi & i) if first multi && print(io, "(") @@ -87,7 +87,7 @@ function Base.show(io::IO, m::MIME"text/plain", t::Type{<:BitFlag}) print(io, "BitFlag ") Base.show_datatype(io, t) print(io, ":") - for (i, sym) in namemap(t) + for (sym, i) in pairs(namemap(t)) print(io, "\n", sym, " = ") show(io, Integer(i)) end @@ -245,15 +245,14 @@ function _bitflag_impl(__module__::Module, typename::Symbol, basetype::Type{<:Un ebasetype = esc(basetype) n = length(names) - namemap = Vector{Tuple{basetype, Symbol}}(undef, n) instances = Vector{Expr}(undef, n) flagconsts = Vector{Expr}(undef, n) @inbounds for ii in 1:length(names) sym, val = names[ii], values[ii] - namemap[ii] = (val, sym) instances[ii] = :(bitcast($etypename, $val)) flagconsts[ii] = :(const $(esc(sym)) = bitcast($etypename, $val)) end + namemap = NamedTuple{(names...,)}((values...,)) blk = quote # bitflag definition diff --git a/test/runtests.jl b/test/runtests.jl index aea7bae..7fecfaa 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -93,6 +93,33 @@ end @test Integer(flag7b) === UInt8(2) #end +#@testset "Internal definitions" begin + # Underlying integer types + @test BitFlags.basetype(Flag5) === UInt32 + @test BitFlags.basetype(Flag6) === UInt8 + + # Whether flag has an explicit zero + @test !BitFlags.haszero(Flag3) + @test BitFlags.haszero(Flag4) + + # Key-Value mapping + @test BitFlags.namemap(Flag5) isa NamedTuple{(:flag5a, :flag5b), NTuple{2, UInt32}} + @test BitFlags.namemap(Flag6) isa NamedTuple{(:flag6a, :flag6b, :flag6c), NTuple{3, UInt8}} + # Ensure the mapping can be used in a type-inferrable way + function isset_nt(x::B) where {T, B <: BitFlag{T}} + nm = BitFlags.namemap(B) + K, V = keys(nm), values(nm) + tf = (BitFlags.haszero(B) && iszero(T(x))) ? iszero.(V) : (!iszero).(V .& T.(x)) + return NamedTuple{K}(tf) + end + @test @inferred isset_nt(flag3a) == (; flag3a = true, flag3b = false, flag3c = false) + @test @inferred isset_nt(flag3b) == (; flag3a = false, flag3b = true, flag3c = false) + @test @inferred isset_nt(flag3b | flag3c) == (; flag3a = false, flag3b = true, flag3c = true) + @test @inferred isset_nt(flag4a) == (; flag4a = true, flag4b = false, flag4c = false) + @test @inferred isset_nt(flag4b) == (; flag4a = false, flag4b = true, flag4c = false) + @test @inferred isset_nt(flag4b | flag4c) == (; flag4a = false, flag4b = true, flag4c = true) +#end + #@testset "Error conditions" begin @test_throws ArgumentError("no arguments given for BitFlag Foo"