Giter Site home page Giter Site logo

Comments (9)

stephenberry avatar stephenberry commented on June 9, 2024 1

Your single lambda approach invokes the function for both reading and writing. To split out different behaviors for reading and writing with lambdas you can register separate lambdas using glz::custom.

A basic example:

struct custom_load_t
{
   std::vector<int> x{};
   std::vector<int> y{};

   struct glaze
   {
      static constexpr auto read_x = [](auto& s) -> auto& { return s.x; };
      static constexpr auto write_x = [](auto& s) -> auto& { return s.y; };
      static constexpr auto value = glz::object("x", glz::custom<read_x, write_x>);
   };
};

from glaze.

stephenberry avatar stephenberry commented on June 9, 2024 1

You probably have a good reason for using unions, but Glaze also has a lot of support for std::variant that can achieve similar goals: docs/variant-handling.md

from glaze.

stephenberry avatar stephenberry commented on June 9, 2024 1

The problem is that I don't think C++ has a mechanism to determine the alternative types of a union. Whereas, with a std::variant we can look at the types at compile time and build logic about how to serialize/deserialize it.

In the glz::meta we could have the user list the union types. This requires more typing, but I think makes sense.

I do think it would be useful to add union support to Glaze (for trivial types). I'll update this issue's name appropriately.

from glaze.

pawcam avatar pawcam commented on June 9, 2024

Thanks for the quick response! This looks like what I'm going for and I'll give it a try.

In the meantime I came up with another solution where I define a "normalizing" struct to act as a shim for reading/writing data that just uses the glz::meta approach with normal reflection

template <>
struct glz::meta<normalized_data>
{
  using T = normalized_data;
  static constexpr auto value = object(
      "actor-name"                 , &T::actor_name
      "actor-type"                 , &T::actor_type
    )
}


struct normalized_data
{
   string actor_name
   string actor_type
}

struct Data
{
  union u1
  int unionType
}

void serialize(Data &data)
{
  normalized_data.field1 = transformUnion(data.u1, data.unionType)
  glz::write(normalized_data, buffer)
}

I'll weigh the two options if I ever need to add new structs, and if I ever move to variants I'll give that a second look.

One last question (slightly related), my glz::meta seems to output the incorrect key (just uses member name for reflection rather than how I specified it). Is there an option needed in order to enable dasherized/hyphenated key names? Below is the output

{"actor_name":"John Smith","actor_type":"developer"}

from glaze.

stephenberry avatar stephenberry commented on June 9, 2024

Cool, that sounds good. And, std::variant is really nice if you get around to experimenting with it.

One last question (slightly related), my glz::meta seems to output the incorrect key (just uses member name for reflection rather than how I specified it). Is there an option needed in order to enable dasherized/hyphenated key names? Below is the output

This issue is something I haven't seen before. Maybe your glz::meta specialization needs to be declared after your class, or it isn't in the same translation unit as your serialization. If you could provide me with a simple example of code that produces the incorrect output that would help me find the problem.

from glaze.

pawcam avatar pawcam commented on June 9, 2024

No problem. I think it's what you're saying, I changed the names entirely and they don't seem to have any effect.

This should be a working example (I added a bit more of my actual code to illustrate what's happening):
glazeMetadata.h

#include "Reflection.h"

#include <glaze/glaze.hpp>

namespace glz {

template <>
struct meta<event::Data>
{
  using T = event::Data;
  static constexpr auto value = object(
      "actor-name"               , &T::actor_name
    , "actor-type"                , &T::actor_type
    , "job-id"        , &T::job_id
  );
};

} // namespace glz

Reflection.h

namespace event
{
  struct Data
  {
    uint32_t         job_id;
    std::string      actor_name;
    std::string      actor_type; 
  };

} // namespace event

These two structs are in separate header files inside of the same library, built using CMake. Here's my test code:

event::Data data{};
data.job_id = 1;
data.actor_name = "John Smith";
data.actor_type = "developer";
std::string_view buffer;
glz::write_json(data, buffer);

from glaze.

pawcam avatar pawcam commented on June 9, 2024

No need to chase this down, it was the include order that was throwing things off. I fixed it by just moving the meta specialization into the same header.

Appreciate all the help!

from glaze.

pawcam avatar pawcam commented on June 9, 2024

Sorry to reopen this, but kind of ran into trouble with this approach further down the line, but it seems like there isn't a way to access the data read from the json string inside my lambda:

template<>
struct glz::meta<Data>
{
  static constexpr auto read_type = [](const auto &s)  {
    return // how do I get the raw string value read from JSON here in order to transform it back into my struct field?
  };
  static constexpr auto write_type = [](const auto& s) {
    return printTypeString(s.type));
  };

  static constexpr auto value = object( "type"            , glz::custom<read_type, write_type>)
}

When I run this code all I get in the lambda is the empty struct Im trying to read into. I guess the real thing I'm after here is full control over how data gets written/read from json based on access to both the struct we're reading into, and the raw json data. Is there a way to pass more arguments to custom readers and writers than just const auto&?

something like:
static constexpr auto read_type = [](const auto &s) {
string tmp = glz::read("type")
return toType(tmp); // how do I get the raw string value read from JSON here in order to transform it back into my struct field?
};

from glaze.

pawcam avatar pawcam commented on June 9, 2024

I think I see how to do this now based on the compile error messages

static constexpr auto const read_instrument_type = [](Data&s, const std::string_view& value) -> void {
    s.type = serialize::FieldHelper::parseInstrumentTypeString(value);
  };
  static constexpr auto write_instrument_type = [](const auto& s) {
    return printType(type);
  };

It still doesn't eliminate the need for tagged union support (I'd imagine it'd be very similar to the variant support) We do have strong reasons for wanting to control the size of the union but if we ever make the change it should work for our purposes. Are there any plans to support tagged unions? e.g.

union typeUnion
{
   type1 cool
   type2 beans
}
enum type;

I started down my own workaround to imitate what you do for variant, but it seems there's no support for union:

template<>
struct meta<typeUnion>
{
  using T = typeUnion;
  static constexpr std::string_view tag = "type";
  static constexpr auto ids = std::array{"type1Tag", "type2Tag};
};
/Serializer.h:82:26: error: no matching function for call to ‘read_json(typeUnion&, std::string_view&)’
   82 |     errc = glz::read_json(m_union, buffer);
      |            ~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
In file included from /home/user/.cache/CPM/glaze/2c5e2f53ecc3ddc14bae077f3e1c198222641b8e/include/glaze/json/json_ptr.hpp:13,
                 from /home/user/.cache/CPM/glaze/2c5e2f53ecc3ddc14bae077f3e1c198222641b8e/include/glaze/binary/write.hpp:11,
                 from /home/user/.cache/CPM/glaze/2c5e2f53ecc3ddc14bae077f3e1c198222641b8e/include/glaze/binary/ptr.hpp:7,
                 from /home/user/.cache/CPM/glaze/2c5e2f53ecc3ddc14bae077f3e1c198222641b8e/include/glaze/binary.hpp:7,
                 from /home/user/.cache/CPM/glaze/2c5e2f53ecc3ddc14bae077f3e1c198222641b8e/include/glaze/glaze.hpp:35,
                 from Reflection.h:8,
                 from Serializer.h:4,
                 from SerializerTest.cpp:9:
/home/user/.cache/CPM/glaze/2c5e2f53ecc3ddc14bae077f3e1c198222641b8e/include/glaze/json/read.hpp:2709:37: note: candidate: ‘template<class T, class Buffer>  requires  read_json_supported<T> glz::parse_error glz::read_json(T&, Buffer&&)’
 2709 |    [[nodiscard]] inline parse_error read_json(T& value, Buffer&& buffer) noexcept
      |                                     ^~~~~~~~~
/home/user/.cache/CPM/glaze/2c5e2f53ecc3ddc14bae077f3e1c198222641b8e/include/glaze/json/read.hpp:2709:37: note:   template argument deduction/substitution failed:
/home/user/.cache/CPM/glaze/2c5e2f53ecc3ddc14bae077f3e1c198222641b8e/include/glaze/json/read.hpp:2709:37: note: constraints not satisfied
...
/home/user/.cache/CPM/glaze/2c5e2f53ecc3ddc14bae077f3e1c198222641b8e/include/glaze/core/opts.hpp:223:12:   required for the satisfaction of ‘read_json_supported<T>’ [with T = typeUnion]
/home/user/.cache/CPM/glaze/2c5e2f53ecc3ddc14bae077f3e1c198222641b8e/include/glaze/core/opts.hpp:223:34:   in requirements  [with T = typeUnion]
/home/user/.cache/CPM/glaze/2c5e2f53ecc3ddc14bae077f3e1c198222641b8e/include/glaze/core/opts.hpp:223:53: note: the required expression ‘glz::detail::from_json<typename std::remove_cvref<_Tp>::type>{}’ is invalid
  223 |    concept read_json_supported = requires { detail::from_json<std::remove_cvref_t<T>>{}; };
      |                                                     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

from glaze.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.