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

[meta] Automatic opaque serialization #1409

Open
wants to merge 13 commits into
base: master
Choose a base branch
from

Conversation

jpeletier
Copy link
Contributor

@jpeletier jpeletier commented Oct 21, 2024

Note: must merge #1405 first

This PR builds on the previous two to add automatic opaque serialization for those opaques defining the appropriate get_* callbacks.

When defining serialization for an opaque, you have to define a serialize callback. If this callback is not defined, serialization will fail.

With this change, when a serialize callback is not defined, the meta module will try to find a way to serialize the opaque if the opaque has defined another callback that can be used.

This is useful if you have already defined a get_ callback that does the work and don't want to define a serializer.

If you do define a serializer, the serializer takes precedence and it is used as before.

For example:

  struct IntOpaque {
    int value;
  };

// BEFORE:
  ecs.component<IntOpaque>()
      .opaque(flecs::I32)
      .serialize([](const flecs::serializer *ser, const IntOpaque *data) -> int { 
        ser->value(data->value);
        return 0; 
    });

// Now: 
  ecs.component<IntOpaque>()
    .opaque(flecs::I32)
    .get_int([](const IntOpaque *data) -> int64_t { 
      return data->value; 
    });

It is still recommended to write a serializer if what you are doing with the type is to fully serialize it to JSON or something similar.

If, however, you are using reflection to access portions of opaque data randomly, the serializer could be slower/inefficient because it dumps the whole content, whereas the get_ callbacks provide the opaque with a way to go straight to the requested data.

For example, the following will now work without a serializer:

  using IntVector = std::vector<int>;

  ecs.component<IntVector>()
      .opaque(ecs.vector<int>())
      .get_element([](const IntVector *src, size_t i) -> const void * { return src->data() + i; })
      .count([](const IntVector *src) -> size_t { return src->size(); });

  IntVector vec = {1, 2, 3};

  // work with IntVector accessing a random element:
  flecs::cursor cur(ecs, ecs.component<IntVector>(), &vec);
  cur.push();
  cur.elem(2);
  std::cout << "vec[2] = " 
            << cur.get_int()  // will call opaque's get_element()
            << std::endl;

  // Can also serialize the whole vector to JSON, without having to write a serializer,
  // at a small performance cost:
  std::cout << "JSON: " << ecs.to_json(&vec) << std::endl;

  // output:
  // vec[2] = 3
  // JSON: [1, 2, 3]

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 this pull request may close these issues.

1 participant