Skip to content

Conversation

@philippeVerney
Copy link

What is the purpose of the change

This pull request allows (C++ 17) std::optional structure to be encoded and decoded.

Verifying this change

This change added tests and can be verified as follows:

  • Added test in test/SpecificTests.cc

Documentation

  • Does this pull request introduce a new feature? yes
  • If yes, how is the feature documented? Same documentation than for other specific specific encoder/decoder

@github-actions github-actions bot added the C++ Pull Requests for C++ binding label Nov 13, 2025
case 1: {
T t;
avro::decode(d, t);
s.emplace(t);
Copy link
Contributor

Choose a reason for hiding this comment

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

std::move(t) here could avoid a copy. Compiler Explorer

Copy link
Author

Choose a reason for hiding this comment

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

100% agree. I change that.

Copy link
Author

Choose a reason for hiding this comment

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

I actually even preferred in place construction. Hoping it is fine with you.

#include "AvroTraits.hh"
#include "Config.hh"
#include "Decoder.hh"
#include "Encoder.hh"
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
#include "Encoder.hh"
#include "Exception.hh"

for the new usage at https://github.com/apache/avro/pull/3545/files#diff-6a9c42629e99021e3a2ea7e61e2c364940c9e04228a8b382ea47032f04d44c74R192

/**
* Encodes a given value.
*/
static void encode(Encoder &e, const std::optional<T> &b) {
Copy link
Member

Choose a reason for hiding this comment

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

This makes an assumption that the schema is ["null", T].
This is true most of the time but it is not mandatory. Without having the schema in scope I see no way how to improve it.

Copy link
Author

Choose a reason for hiding this comment

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

I add this remark in a comment not to lost it. Thanks.
Could you give me another schema example of an AVRO optional please.
I have some "optional" as ["null", U, V, T, ...] but I map them to std::variant for now (other PR to come maybe)

Copy link
Member

Choose a reason for hiding this comment

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

AVRO optional

There is no such thing as Avro optional. The type is Union. It can have from 2 to N variants.
"null" is not a mandatory variant. It could be at any index in the variants, but usually it is the first one. Without a Schema it is a wild guess.

Copy link
Author

Choose a reason for hiding this comment

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

Got it now, thanks for the explanation.
I don't see anything else to improve about your remark now that I added the comment in the documentation of the code_traits.
However, I now perfectly share your concern.

Copy link
Contributor

Choose a reason for hiding this comment

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

I like the idea of standard encoding for optional<T>. Users are expected to use it only if the schema is [null, T]. We can even make the code generator use optional<T> whenever the schema is [null, T]. This will break compatibility, of course. So there should be a switch for the generator to make this optional (pun intended).

Since this PR does not break compatibility and makes its intent clear, I think, we should merge it.

*/
static void decode(Decoder &d, std::optional<T> &s) {
size_t n = d.decodeUnionIndex();
if (n >= 2) { throw avro::Exception("Union index too big"); }
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
if (n >= 2) { throw avro::Exception("Union index too big"); }
if (n >= 2) { throw avro::Exception("Union index too big for optional (expected 0 or 1, got " + std::to_string(n) + ")"); }

Add missing header.
Improve error message.
Document expected corresponding schema.
Prefere optional.reset() over optional = std::nullopt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C++ Pull Requests for C++ binding

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants