getml / reflect-cpp

A C++20 library for fast serialization, deserialization and validation using reflection. Supports JSON, BSON, CBOR, flexbuffers, msgpack, TOML, XML, YAML / msgpack.org[C++20]
https://getml.github.io/reflect-cpp/
MIT License
821 stars 66 forks source link

Transforming class/object into array during serialization/deserialization #84

Closed Lazrius closed 2 months ago

Lazrius commented 3 months ago

Hello again. I've read the documentation quite a bit and don't think I've missed it, but I was wondering if it is possible to convert an object into an array type for the purposes of serialization and then convert it back into an object when going the other way around?

An example: We have an internal Vector class that represents three float values. I wrote the following code to handle it, but it's less than ideal:

namespace rfl::parsing {
    struct VectorImpl
    {
        float arr[3];

        static VectorImpl from_class(const Vector& val) noexcept {
            return VectorImpl{{val.x, val.y, val.z}};
        }

        [[nodiscard]] Vector to_class() const { return Vector{arr[0], arr[1], arr[2]}; }
    };

    template <class ReaderType, class WriterType>
    struct Parser<ReaderType, WriterType, Vector>
        : CustomParser<ReaderType, WriterType, Vector, VectorImpl> {};

} // namespace rfl::parsing

which when passing in some example vectors, we get the following json:

  "pos": {
    "arr": [
      -39902.37109375,
      -197.51206970214844,
      -31097.71875
    ]
  },
  "rot": {
    "arr": [
      -73.62753295898438,
      -58.3359375,
      69.4403305053711
    ]
  }

Obviously not perfect. We'd more be looking for the following:

  "pos": [
      -39902.37109375,
      -197.51206970214844,
      -31097.71875
  ],
  "rot": [
      -73.62753295898438,
      -58.3359375,
      69.4403305053711
  ]

Is this possible, and if so, do you know what I need to change to make it happen?

Thanks again for your great project!

liuzicheng1987 commented 3 months ago

You could try to have the array as a ReflectionType in your VectorImpl:

https://github.com/getml/reflect-cpp/blob/main/docs/custom_classes.md

C arrays are tricky, because they can't be copied, but std::array will most certainly work.

Lazrius commented 2 months ago

Forgot to follow up, my apologies.

This is the code we used in the end and it worked very well, thank you again.

    struct VectorImpl
    {
            using ReflectionType = std::array<float, 3>;
            std::array<float, 3> arr;

            static VectorImpl from_class(const Vector& val) noexcept
            {
                return VectorImpl{
                    { val.x, val.y, val.z }
                };
            }

            [[nodiscard]]
            Vector to_class() const
            {
                return Vector{ arr[0], arr[1], arr[2] };
            }
    };

    template <class ReaderType, class WriterType, class ProcessorsType>
    struct Parser<ReaderType, WriterType, Vector, ProcessorsType> : CustomParser<ReaderType, WriterType, ProcessorsType, Vector, VectorImpl>
    {};