fraillt/bitsery

Vector of variants with a bit-packed type

Net5F opened this issue · 2 comments

Net5F commented

Hello! I've run into another question.

I have a struct that I'm trying to serialize. It has a vector of variants:

struct Foo {
    using MyVariant = std::variant<Bar, Baz>;
    
    std::vector<MyVariant> variantVector;
};

Normally, I can serialize it as such:

template<typename S>
void serialize(S& serializer, MyVariant& myVariant)
{
    std::visit([&](auto& value) { serializer.object(value); },
               myVariant);
}

template<typename S>
void serialize(S& serializer, Foo& foo)
{
    serializer.container(foo.variantVector, 2,
                         [](S& serializer, MyVariant& variant) {
                             serializer.ext(variant, bitsery::ext::StdVariant{});
                         });
}

However, this breaks when I add a type that uses bit packing to the variant.
I figure the issue is needing to enable bit packing (the type expects bit packing to be enabled in the calling scope), so I've tried to do the following, but no luck:

template<typename S>
void serialize(S& serializer, Foo& foo)
{
    serializer.enableBitPacking([&](typename S::BPEnabledType& sbp) {
        sbp.container(foo.variantVector, 2,
                      [](S& serializer, MyVariant& variant) {
                          serializer.ext(variant, bitsery::ext::StdVariant{});
                      });
    });
}

Here's my bit-packed type for reference, in case it's useful:

struct Input {
    enum Type : Uint8 { XUp, XDown, YUp, YDown, ZUp, ZDown, Count, None };
    enum State : Uint8 { Released, Pressed };

    using StateArr = std::array<State, Type::Count>;
    StateArr inputStates{};
};

template<typename S>
void serialize(S& serializer, Input& input)
{
    serializer.container(input.inputStates, [](typename S::BPEnabledType& sbp,
                                               Input::State& inputState) {
        constexpr bitsery::ext::ValueRange<Input::State> range{
            Input::State::Released, Input::State::Pressed};
        sbp.ext(inputState, range);
    });
    serializer.adapter().align();
}

Any ideas on how I can get this to compile?

I think the problem is in inner closure. spb.container is using bit-packing enabled, you also need to pass in the same type in inner lambda

[](typename S::BPEnabledType& serializer, MyVariant& variant) {
    serializer.ext(variant, bitsery::ext::StdVariant{});
});

A good thing is that you can nest bp-enabled types, e.g. if you call enableBitPacking while already in bp-enabled scope, this operation is no-op.

Net5F commented

Good eye, that did it! Thanks 😄