Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert into a struct or named tuple #7

Closed
sairus7 opened this issue Nov 7, 2022 · 3 comments · Fixed by #10
Closed

Convert into a struct or named tuple #7

sairus7 opened this issue Nov 7, 2022 · 3 comments · Fixed by #10

Comments

@sairus7
Copy link

sairus7 commented Nov 7, 2022

I want to use this as a packed representation for a structure (or a named tuple) with bool fields.
Can I transform this into such a structure?

@bitflag BitFlagName::UInt32 begin
    flag_x
    flag_y
    flag_z
end

inp = flag_x | flag_y

out1 = (flag_x = true, flag_y = true, flag_z = false)

struct Foo
    flag_x::Bool
    flag_y::Bool
    flag_z::Bool
end

out2 = Foo(true, true, false)

# how can I convert inp into out1 and out2?
do_something1(inp) === out1
do_something2(inp) === out2

And then I need to wrap an array of bitflags into a StructArray with fields stored as BitVectors:

vec = [flag_x, flag_y, flag_x | flag_y]
svec1 = StructVector(vec) 
svec1.flag_x isa BitVector === true
svec1[1] isa BitFlagName == true # or maybe a named tuple?

svec2 = StructVector{Foo}(vec)  
svec2[1] isa Foo # struct
svec2.flag_x isa BitVector === true
@jmert
Copy link
Owner

jmert commented Nov 7, 2022

The key to the transformations you're looking for is the unexported BitFlags.namemap function. For example, you can write a specific conversion for your bit flag type to convert to a NamedTuple like:

julia> using BitFlags

julia> @bitflag BitFlagName::UInt32 begin
           flag_x
           flag_y
           flag_z
       end

julia> function Base.convert(::Type{NamedTuple}, flag::BitFlagName)
           T = BitFlags.basetype(BitFlagName)
           return NamedTuple(sym => T(flag) & v != zero(T) for (v, sym) in BitFlags.namemap(BitFlagName))
       end

julia> convert(NamedTuple, flag_x | flag_y)
(flag_x = true, flag_y = true, flag_z = false)

The conversion to your Foo struct can then make use of the NamedTuple conversion as well:

julia> struct Foo
           flag_x::Bool
           flag_y::Bool
           flag_z::Bool
       end

julia> function Base.convert(::Type{Foo}, flag::BitFlagName)
           nt = convert(NamedTuple, flag)
           foo_args = (getfield(nt, k) for k in fieldnames(Foo))
           return Foo(foo_args...)
       end

julia> convert(Foo, flag_x | flag_y)
Foo(true, true, false)

I don't know much StructArrays in general (so I don't have an answer for how to fake a field in the first example, which would be a question for the StructArray implementers), but the second basically falls out of the conversion to your struct Foo:

julia> using StructArrays

julia> svec2 = StructVector(convert.(Foo, [flag_x, flag_y, flag_x | flag_y]))
3-element StructArray(::Vector{Bool}, ::Vector{Bool}, ::Vector{Bool}) with eltype Foo:
 Foo(true, false, false)
 Foo(false, true, false)
 Foo(true, true, false)

julia> svec2[1]
Foo(true, false, false)

julia> BitVector(svec2.flag_x)
3-element BitVector:
 1
 0
 1

@sairus7
Copy link
Author

sairus7 commented Nov 7, 2022

Thanks! Also, for performance reasons namemap can use a Tuple instead of a Vector, since it has static length.
Or maybe even a NamedTuple itself (most suitable for a static map).

Also it can be generated from unrolled loop, like here: https://gist.github.com/sairus7/c370c8972d9466b2c621affbeb98a9c7

@jmert
Copy link
Owner

jmert commented Nov 19, 2022

@sairus7 I've release v0.1.7 which changes BitFlags.namemap to return a NamedTuple. The new test added in #10 also effectively uses the function you were asking for to test inferrability.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants