Skip to content

Seamlessly support non-default-constructable custom class deserialization#1087

Open
mzoll wants to merge 17 commits into
jbeder:masterfrom
mzoll:master
Open

Seamlessly support non-default-constructable custom class deserialization#1087
mzoll wants to merge 17 commits into
jbeder:masterfrom
mzoll:master

Conversation

@mzoll

@mzoll mzoll commented Mar 3, 2022

Copy link
Copy Markdown

The current API of the convert<T>::decode construct is limited to default constructable structs with visible members only. This is limiting and does not follow RAII.

The here patch allows to declare in the custom 'struct convert' for any type T a decode method by slightly different, but more instructive, signature T convert<T>::decode(const Node& node). Within that method T can be constructed by the user from the data serialized from node and the result returned without the need to manipulate the members of an uninitialized reference. Problems in the deserialization process are marked by throwing the DecodeException, effectively replacing the old convoluted bool return signaling deserialization success.

While users are free to implement this new API the old API is still supported in static code-path switches based on the decode-signature detected.

The complete documentation is found at the bottom of docs/Tutorial.md

tests have been added and pass.

This patch closes #993
This patch also shows an alternative solution to merge request #1010

@SGSSGene SGSSGene left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see the need/desire for a converter that works for non defaultable types.

Changing the API is not an option. This would break to much and currently the goal is to maintain this library to keep it compatible and reduce number of bugs.

So it would need some mechanism that allows for old and new API to work together.

Additionally, I am not satisfied with the conversion from exception to return value paths:

try {
   ...
  } catch(const conversion::DecodeException& e) {
    return false; //not doing this breaks upstream functionality
  } catch (...) {
    throw;
  }

This in my eyes should not be. In c++23 I would use std::expected and in c++17 std::optional not sure what to do in c++11. Maybe std::variant?

Comment thread docs/Tutorial.md
Comment on lines +204 to +206
Observe that in the above example the custom type is, decalred as
a struct, explicit default constructable and all its members are
exposed. For non default constructable types like

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor typo:

Suggested change
Observe that in the above example the custom type is, decalred as
a struct, explicit default constructable and all its members are
exposed. For non default constructable types like
Observe that in the above example the custom type is, declared as
a struct, explicit default constructable and all its members are
exposed. For non default constructable types like

Comment thread docs/Tutorial.md
rhs.x = node[0].as<double>();
rhs.y = node[1].as<double>();
rhs.z = node[2].as<double>();
return true;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrong return value. Should be rhs not true.

Suggested change
return rhs;

Comment thread docs/Tutorial.md
Comment on lines +214 to +216
NonDefCtorVec3(double x, double y, double z)
: Vec3() { this->x=x; this->y=y; this->z=z;
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Proper initialization of variables:

Suggested change
NonDefCtorVec3(double x, double y, double z)
: Vec3() { this->x=x; this->y=y; this->z=z;
};
NonDefCtorVec3(double x, double y, double z)
: Vec3{x, y, z}
{}

Comment thread docs/Tutorial.md
return true;
}
};
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, maybe convert<Vec3> should keep the old API?

Comment on lines +62 to +68

// static Node decode(const Node& node) {
// throw std::runtime_error("this should not have been encountered");
// Node rhs;
// rhs.reset(node);
// return rhs;
// }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this be removed?

Comment thread test/node/node_test.cpp
Comment on lines +52 to +66
class NonDefCtorVec3 : public Vec3 {
using Vec3::x;
using Vec3::y;
using Vec3::z;
public:
NonDefCtorVec3(double x, double y, double z)
: Vec3() {
this->x=x;
this->y=y;
this->z=z;
};
bool operator==(const NonDefCtorVec3& rhs) const {
return x == rhs.x && y == rhs.y && z == rhs.z;
}
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs same adjustments as in the Tutorial.md

Comment thread docs/Tutorial.md
Comment on lines +210 to +212
using Vec3::x;
using Vec3::y;
using Vec3::z;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using statements are not required.

Suggested change
using Vec3::x;
using Vec3::y;
using Vec3::z;

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.

custom converter for non default-constructable data-types

2 participants