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

Simple nested message fails #4

Open
Erhannis opened this issue Feb 4, 2025 · 2 comments
Open

Simple nested message fails #4

Erhannis opened this issue Feb 4, 2025 · 2 comments

Comments

@Erhannis
Copy link

Erhannis commented Feb 4, 2025

Consider the following proto file.

syntax = "proto3";

message Address {
  uint64 lsb_six_bytes = 1;
}

message MTest1 {
  Address address = 1;
}

message MTest2 {
  oneof val {
    Address ADDRESS = 1;
  }
}

MTest2 works, and MTest1 does not. Specifically, encoding MTest1 doesn't include address. See example project:

https://github.com/Erhannis/mpb_bug_example

It's based off the micropb basic example. MTest2 passes the assertion (and appears to actually de/serialize correctly), while MTest1 fails the assertion (and in fact serializes to 0 bytes). Assertion fail:

thread 'main' panicked at src/main.rs:35:3:
assertion `left == right` failed
  left: MTest1 { address: Address { lsb_six_bytes: 6618611909121 }, _has: _Hazzer([0]) }
 right: MTest1 { address: Address { lsb_six_bytes: 0 }, _has: _Hazzer([0]) }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
@Erhannis
Copy link
Author

Erhannis commented Feb 4, 2025

Ok, I think I figured it out. In the readme you mention "Note that a field will be considered empty (and ignored by the encoder) if its bit in the hazzer is not set, even if the field itself has been written." This appears to be the case for nested messages; it works if I do either

  obj.set_address(Address {lsb_six_bytes: 0x060504030201});

or

  obj.address = Address {lsb_six_bytes: 0x060504030201};
  obj._has = obj._has.init_address();

It's not clear to me though why I need init or w/e for an Address, but not for a plain uint64.

@YuhanLiin
Copy link
Owner

The reason is because a plain uint64 is not considered an optional field, but a nested message such as Address is always optional, so the hazzer bit is required to track presence. Easiest way to set it is via obj._has.set_address().

I am considering changing this API in the future, since it's becoming a common footgun.

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

No branches or pull requests

2 participants