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

archive derive of PartialEq for rkyv - 0.4.x #959

Merged
merged 6 commits into from Oct 10, 2023

Conversation

mkatychev
Copy link
Contributor

@mkatychev mkatychev commented Feb 10, 2023

This PR resolves PartialEq compilation errors for types that derive rkyv::Archive:

error[E0277]: can't compare `chrono::datetime::ArchivedDateTime<Utc>` with `DateTime<Utc>`
   --> common/src/transaction.rs:142:5
    |
142 |     rkyv::Archive,
    |     ^^^^^^^^^^^^^ no implementation for `chrono::datetime::ArchivedDateTime<Utc> == DateTime<Utc>`
    |
    = help: the trait `PartialEq<DateTime<Utc>>` is not implemented for `chrono::datetime::ArchivedDateTime<Utc>`
    = help: see issue #48214
    = note: this error originates in the derive macro `rkyv::Archive` (in Nightly builds, run with -Z macro-backtrace for more info)

This PR does not address #762 since a new archived object is created, for example ArchivedDateTime<Utc> is derived from DateTime<Utc>, but does preserve feature inclusivity.

I don't think this change merits tests as the object created is not directly accessible for comparison as shown in the rkyv basic example but happy to discuss.

@mkatychev mkatychev changed the base branch from main to 0.4.x February 10, 2023 17:50
@mkatychev mkatychev changed the title Feat/archive peq rkyv 0.4.x archive derive of PartialEq for rkyv - 0.4.x backport Feb 10, 2023
@esheppa
Copy link
Collaborator

esheppa commented Feb 12, 2023

Thanks for this @mkatychev - sorry to be a pain but do you mind doing a git rebase -i HEAD~1 or similar so that this gets a new commit hash and the CI runs (I think the change from main to 0.4.x is currently preventing it running)

@mkatychev
Copy link
Contributor Author

@esheppa After testing, I had to introduce a couple of changes to enable safe deserlialization.
Using the README example from the rkyv repository as reference, it seems bytecheck::CheckBytes has to be derived as well if one wants to avoid using unsafe:

// You can use the safe API for fast zero-copy deserialization
let archived = rkyv::check_archived_root::<Test>(&bytes[..]).unwrap();
assert_eq!(archived, &value);

// Or you can use the unsafe API for maximum performance
let archived = unsafe { rkyv::archived_root::<Test>(&bytes[..]) };
assert_eq!(archived, &value);

This seems like a core part of the way rkyv should work so I added a PR upstream to re-export bytecheck: rkyv/rkyv#340.

In the meantime however, it made the most sense to add bytecheck as an optional dependency to chrono while the PR above is still under review.

@mkatychev mkatychev changed the title archive derive of PartialEq for rkyv - 0.4.x backport archive derive of PartialEq for rkyv - 0.4.x Feb 13, 2023
@mkatychev
Copy link
Contributor Author

mkatychev commented Feb 13, 2023

toolchain: 1.38.0
- uses: Swatinem/rust-cache@v1
# run --lib and --doc to avoid the long running integration tests which are run elsewhere
- run: cargo test --lib --features unstable-locales,wasmbind,oldtime,clock,rustc-serialize,serde,winapi --color=always -- --color=always
- run: cargo test --doc --features unstable-locales,wasmbind,oldtime,clock,rustc-serialize,serde,winapi --color=always -- --color=always

The dep:feature is supported in rust 1.60 and upwards. Is there any guidelines for how far behind the msrv should be?
Happy to revert to two separate optional dependencies and use #[cfg_attr(all(feature = "bytecheck", feature = "rkyv"), archive_attr(derive(CheckBytes)))]

@djc
Copy link
Contributor

djc commented Feb 14, 2023

For the 0.4.x branch, we're sticking with 1.38 for now, so the two optional deps would be the way forward for now. Thanks!

Cargo.toml Outdated Show resolved Hide resolved
Copy link
Contributor

@jtmoon79 jtmoon79 left a comment

Choose a reason for hiding this comment

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

I visually reviewed. LGTM. However, I know very little about serde internals so I won't be able to spot serde-specific bugs.

Does this change need new test cases?
For example, I see the rkyv project implements a some test macros like pub fn test_archive<T>(value: &T) https://github.com/rkyv/rkyv/blob/master/rkyv_test/src/util.rs#L4
and test cases using those macros like fn archive_containers() https://github.com/rkyv/rkyv/blob/master/rkyv_test/src/test_alloc.rs#L36

Should the definitions here have test cases that exercise the rkyv features?

@mkatychev mkatychev marked this pull request as draft April 5, 2023 23:19
@mkatychev
Copy link
Contributor Author

I visually reviewed. LGTM. However, I know very little about serde internals so I won't be able to spot serde-specific bugs.

Does this change need new test cases? For example, I see the rkyv project implements a some test macros like pub fn test_archive<T>(value: &T) https://github.com/rkyv/rkyv/blob/master/rkyv_test/src/util.rs#L4 and test cases using those macros like fn archive_containers() https://github.com/rkyv/rkyv/blob/master/rkyv_test/src/test_alloc.rs#L36

Should the definitions here have test cases that exercise the rkyv features?

I did a bit of upstream work in bytecheck and rkyv that I have to reflect in this PR. As such I've moved this to draft for when I get around to backporting the changes.

@mkatychev
Copy link
Contributor Author

mkatychev commented Apr 13, 2023

@jtmoon79 I'm going to wait for rkyv to release 0.8 as that allows bytecheck errors to implement Send + Sync before marking this ready for review.


I know very little about serde internals so I won't be able to spot serde-specific bugs

So the derive(Serialize, Deserialize) mentioned above are actually imported as rkyv::Serialize and rkyv::Deserialize respectively rather than serde::Serialize and serde::Deserialize.
There's some info on how that's done here.
rkyv is specifically used to allow a T::to_bytes()? and T::from_bytes(bytes)? implementation rather than as an API library that would allow serialization to various formats (such as serde) which compile time bounds checking.

Without the validation feature flag, the current use of rkyv in chrono is limited to unsafe blocks. By adding #[archive(check_bytes)] to the various chrono structs already using #[derive(rkyv::Archive)] these structs can be used in safe code as well.


Does this change need new test cases?

Other than the codeblock here:

chrono/src/date.rs

Lines 553 to 566 in 5658c49

// This boilerplate is a shortcoming of the `Derive` macro.
// See: https://github.com/rkyv/rkyv/issues/333
#[cfg(feature = "rkyv-validation")]
impl<Tz: TimeZone> fmt::Debug for ArchivedDate<Tz>
where
Tz: Archive,
<Tz as Archive>::Archived: fmt::Debug,
<<Tz as TimeZone>::Offset as Archive>::Archived: fmt::Debug,
<Tz as TimeZone>::Offset: fmt::Debug + Archive,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Date").field("date", &self.date).field("offset", &self.offset).finish()
}
}

This PR doesn't really introduce any rust code since these derives will fail at compile time. The most you'd have to do is see if cargo check --features rkyv-validation fails (which is how I was testing for regressions during this PR).

This line covers --features rkyv:

- run: cargo hack check --feature-powerset --optional-deps serde,rkyv --skip default --skip __internal_bench --skip __doctest --skip iana-time-zone --skip pure-rust-locales

I'll be sure to add ,rkyv-validation to make sure this gets tested as well.

@Roms1383
Copy link

would you mind adding PartialOrd too ?
inner types support it (tried locally then I realized a PR was already opened).

@mkatychev
Copy link
Contributor Author

@jtmoon79 cargo hack check --feature-powerset should already be covering rkyv-validation feature flag

@mkatychev mkatychev marked this pull request as ready for review June 30, 2023 16:23
@mkatychev mkatychev requested review from jtmoon79 and djc June 30, 2023 16:23
@pitdicker
Copy link
Collaborator

@mkatychev I have yet to go and read up about rkyv. But can I ask for your opinion/review of #762?

@mkatychev
Copy link
Contributor Author

mkatychev commented Jul 7, 2023

@pitdicker I'll post my thoughts in this PR, I'm using this current feature branch in my code, and this section does not impact me:

This new type won't have any traits or methods implemented on it except Deserialize, so it can't be easily used in a zero-copy manner

As long as the rkyv::validation::validators::from_bytes function is used, I don't interact with the intermediate type at all.

rkyv::validation::validators::from_bytes is used with by the derive(rkyv::Archive), archive(check_bytes) combination introduced in this PR so I don't have to worry about le/be.

In essence, the rkyv-validation feature flag bypasses a lot of the motivations of not dealing with an intermediate type.

@mkatychev
Copy link
Contributor Author

@pitdicker what else is needed to move this review forward?

@codecov
Copy link

codecov bot commented Sep 18, 2023

Codecov Report

Merging #959 (a5500af) into 0.4.x (0f19d6b) will increase coverage by 0.04%.
The diff coverage is 86.41%.

@@            Coverage Diff             @@
##            0.4.x     #959      +/-   ##
==========================================
+ Coverage   91.55%   91.60%   +0.04%     
==========================================
  Files          38       38              
  Lines       17355    17430      +75     
==========================================
+ Hits        15889    15966      +77     
+ Misses       1466     1464       -2     
Files Coverage Δ
src/duration.rs 93.22% <100.00%> (+0.29%) ⬆️
src/format/scan.rs 99.25% <100.00%> (ø)
src/month.rs 75.96% <100.00%> (+0.96%) ⬆️
src/naive/date.rs 96.26% <100.00%> (+0.01%) ⬆️
src/naive/datetime/mod.rs 97.73% <ø> (+0.08%) ⬆️
src/naive/datetime/tests.rs 98.89% <100.00%> (+0.02%) ⬆️
src/naive/isoweek.rs 99.15% <100.00%> (+0.98%) ⬆️
src/naive/time/mod.rs 96.67% <ø> (+0.11%) ⬆️
src/naive/time/tests.rs 98.48% <100.00%> (+0.04%) ⬆️
src/date.rs 35.86% <0.00%> (ø)
... and 5 more

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@pitdicker
Copy link
Collaborator

Thank you for your work!

@pitdicker what else is needed to move this review forward?

Me needing to get a little experience with rkyv, because I don't understand it yet 😄. Or a review from @djc.

Copy link
Collaborator

@pitdicker pitdicker left a comment

Choose a reason for hiding this comment

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

What I am missing with the rkyv feature is that we don't have any tests. That is not a fault of this PR, but can you please add some?

I don't think it needs to be more than a check that all types round-trip with rkyv::{to_bytes, from_bytes}.
And maybe include a check that the derived types implement PartialOrd, PartialEq and Debug similar to https://github.com/chronotope/chrono/blob/v0.4.31/src/datetime/tests.rs#L1132. Edit: Better to check (of course) that comparison works against the original type.
That should also make coverage happy.

And can you squash the commits?

Cargo.toml Show resolved Hide resolved
Cargo.toml Outdated Show resolved Hide resolved
src/date.rs Outdated Show resolved Hide resolved
src/datetime/mod.rs Show resolved Hide resolved
src/datetime/mod.rs Outdated Show resolved Hide resolved
Cargo.toml Outdated Show resolved Hide resolved
@pitdicker
Copy link
Collaborator

I'll incorporate the comments and add tests later this week.

@mkatychev No hurry, just a reminder.

@mkatychev
Copy link
Contributor Author

@pitdicker apologies for delay, I will start work on this tomorrow.

@mkatychev mkatychev marked this pull request as draft September 28, 2023 22:02
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "rkyv", derive(Archive, Deserialize, Serialize))]
#[cfg_attr(feature = "rkyv", archive_attr(derive(Clone, Copy, PartialEq, Eq, Debug, Hash)))]
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
Copy link
Contributor Author

@mkatychev mkatychev Sep 28, 2023

Choose a reason for hiding this comment

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

I sorted the derives alphabetically to better compare against the archive_attr equivalents.

@mkatychev mkatychev marked this pull request as ready for review September 29, 2023 16:13
@mkatychev
Copy link
Contributor Author

@pitdicker this should be ready for review again

@mkatychev
Copy link
Contributor Author

Tagging related issues for ArchivedDateTime:
rkyv/rkyv#333
rust-lang/rust#26925

Copy link
Collaborator

@pitdicker pitdicker left a comment

Choose a reason for hiding this comment

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

Looking good 😄. A few comments, and we have trouble with our MSRV.

Can you squash the commits?

Cargo.toml Outdated
__internal_bench = []

[dependencies]
num-traits = { version = "0.2", default-features = false }
rustc-serialize = { version = "0.3.20", optional = true }
serde = { version = "1.0.99", default-features = false, optional = true }
pure-rust-locales = { version = "0.7", optional = true }
rkyv = { version = "0.7", optional = true }
rkyv = { version = "0.7.42", optional = true }
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
rkyv = { version = "0.7.42", optional = true }
rkyv = { version = "0.7.41", optional = true }

I hope that by setting 0.7.41 as the minimum version and with rkyv/bytecheck#33 that we can get things working with our MSRV.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm curious why 0.7.42 was not able to be found 🤔 🤔

src/duration.rs Outdated Show resolved Hide resolved
src/month.rs Outdated Show resolved Hide resolved
src/naive/isoweek.rs Show resolved Hide resolved
src/date.rs Outdated Show resolved Hide resolved
.github/workflows/test.yml Outdated Show resolved Hide resolved
@mkatychev
Copy link
Contributor Author

Thanks for pushing this through @pitdicker !

@djc
Copy link
Contributor

djc commented Oct 2, 2023

This needs to be rebased and split into clean commits so I can review it. Right now there's too much going on when reviewing all the changes at once (notably reordering of derives while also adding/removing derives) to make this efficient to review.

@mkatychev
Copy link
Contributor Author

@djc I'll rebase the commits later this week, I'll just skip the reordering altogether to make reviewing easier

* specified latest hotfix version of `rkyv` that includes `bytecheck`
  reexport
…ature flags

* added `archive(check_bytes)` derives `rkyv-validation` feature flags
  chrono month::tests::test_rkyv_validation
  chrono naive::date::tests::test_rkyv_validation
  chrono duration::tests::test_rkyv_validation
  chrono naive::datetime::tests::test_rkyv_validation
  chrono naive::isoweek::tests::test_rkyv_validation
  chrono naive::time::tests::test_rkyv_validation
  chrono offset::fixed::tests::test_rkyv_validation
  chrono offset::local::tests::test_rkyv_validation
  chrono weekday::tests::test_rkyv_validation
@mkatychev
Copy link
Contributor Author

@djc This should be ready for review

@djc djc merged commit 02bdd1d into chronotope:0.4.x Oct 10, 2023
36 of 37 checks passed
@djc
Copy link
Contributor

djc commented Oct 10, 2023

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants