-
Notifications
You must be signed in to change notification settings - Fork 219
Add support for bincode v2.0 #821
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
base: main
Are you sure you want to change the base?
Conversation
e619423
to
2d40b0f
Compare
168e645
to
de93dbe
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this @francisbr! As much as I'd love to fix the redundant length bytes, we need to maintain compatibility with the old serde
and bincode
1.x format. If the new bincode
derive macros have a similar concept to serde
's #[with]
for customizing serialization then we could add support for the more compact format that way.
Cargo.toml
Outdated
readme = "README.md" | ||
repository = "https://github.com/uuid-rs/uuid" | ||
version = "1.16.0" # remember to update html_root_url in lib.rs | ||
version = "1.16.1" # remember to update html_root_url in lib.rs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have a script that updates this so we can leave it as 1.16.0
here. I’ll end up releasing it as 1.17.0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, reverted!
src/external/bincode_support.rs
Outdated
|
||
impl Encode for Uuid { | ||
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> { | ||
Encode::encode(self.as_bytes(), encoder) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, in order to maintain the original serde
1.x + bincode
1.x encoding, we'll need to include the redundant length bytes here too. Here's an example original format UUID we can use to test equivalence:
[16, 0, 0, 0, 0, 0, 0, 0, 232, 18, 203, 187, 159, 207, 72, 46, 151, 197, 95, 187, 59, 106, 126, 5]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not 100% sure I understand how that was working. The example you gave me is 24 bytes (more than the 16 or 17 with the length byte).
I added a check in the encode/decode function to check if the config passed is legacy. If so I simply prepend the '16' byte before the UUID. Is that what is needed?
You can see the test_legacy()
test I added, when passing config::legacy()
to the functions, 17 bytes are encoded/decoded.
Sorry if that is not what is needed and I missunderstood.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I thought our original encoding gave us a 1 byte length, but running bincode::serialize
on 1.x gave me what appeared to be a usize
length prefix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks @francisbr! This looks good to me.
Looks like we've got a few build failures here:
|
impl Encode for NonNilUuid { | ||
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> { | ||
self.get().encode(encoder) | ||
} | ||
} | ||
|
||
impl Encode for Hyphenated { | ||
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> { | ||
self.as_uuid().encode(encoder) | ||
} | ||
} | ||
|
||
impl Encode for Simple { | ||
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> { | ||
self.as_uuid().encode(encoder) | ||
} | ||
} | ||
|
||
impl Encode for Urn { | ||
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> { | ||
self.as_uuid().encode(encoder) | ||
} | ||
} | ||
|
||
impl Encode for Braced { | ||
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> { | ||
self.as_uuid().encode(encoder) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't these differ from the serde
impl?
serde
would output strings for these, therefore I believe bincode v1 encodes a string rather than the bytes.
So, if we care that the Uuid
serde impl is the same as the bincode one, these should encode the string representations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah well spotted! We definitely should maintain compatibility on these adapter types too
if encoder.config().int_encoding() == IntEncoding::Fixed { | ||
usize::encode(&16, encoder)?; | ||
} else { | ||
u8::encode(&16, encoder)?; | ||
} | ||
|
||
<&[u8; 16]>::encode(&self.as_bytes(), encoder)?; | ||
|
||
Ok(()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is sufficient and delegates the int encoding implementation to bincode itself
if encoder.config().int_encoding() == IntEncoding::Fixed { | |
usize::encode(&16, encoder)?; | |
} else { | |
u8::encode(&16, encoder)?; | |
} | |
<&[u8; 16]>::encode(&self.as_bytes(), encoder)?; | |
Ok(()) | |
<[u8]>::encode(self.as_bytes().as_slice(), encoder) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Leaning on the impl provided by bincode
itself seems like a good idea. That way we should naturally respect any new options it introduces that might affect encoding that end users may want.
} | ||
|
||
#[cfg(test)] | ||
mod bincode_tests { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Besides testing the roundtrip of encode->decode, we should probably also test the output binary representation of encode. Just to ensure we know what to expect from a Uuid
and its variants (Simple
, etc)
Found some incompatibilities that we need to fix up
Following the latest major release of Bincode, the crate now relies on its own traits (Encode/Decode) it switched away from serde's De/Serialize. This PR is to add a feature flag here to optionally implement these traits on the Uuid structs.
The 2.0 bincode release: https://github.com/bincode-org/bincode/releases/tag/v2.0.0