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

Adds IonData wrapper that uses Ion equivalence for equality #517

Merged
merged 8 commits into from
Apr 25, 2023

Conversation

popematt
Copy link
Contributor

Issue #, if available:

None

Description of changes:

  • Adds IonData, a struct that can wrap anything that implements IonEq.
    • For IonData<Element>, I added some delegations to Element I thought would be required for it to be useful. There's the read_*() functions and annotations(), and value().
  • Adds IonOrd, a trait for a total ordering that is consistent with IonEq.
  • Adds implementations of IonOrd for Element, Value, and others.
  • Moves IonEq from src/ to src/ion_data/ so that all of the Ion-data-model-semantics stuff is in one place.
  • Small, incidental changes:
    • Adds derive PartialOrd and Ord to Bytes
    • Moves Element.ion_type() implementation to Value; Element.ion_type() now delegates to Value.ion_type()
    • Adds IntoIterator impl for &'a Sequence

I have no illusions that this is perfect, but I want to get something started because we need this for handling things like distinct elements efficiently in ion-schema-rust.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@popematt popematt requested a review from zslayton April 21, 2023 16:59
@codecov
Copy link

codecov bot commented Apr 21, 2023

Codecov Report

Patch coverage: 98.09% and project coverage change: +0.25 🎉

Comparison is base (07779eb) 89.07% compared to head (4fda30d) 89.33%.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #517      +/-   ##
==========================================
+ Coverage   89.07%   89.33%   +0.25%     
==========================================
  Files          82       84       +2     
  Lines       13027    13256     +229     
==========================================
+ Hits        11604    11842     +238     
+ Misses       1423     1414       -9     
Impacted Files Coverage Δ
src/binary/decimal.rs 84.00% <ø> (ø)
src/element/list.rs 83.87% <ø> (+9.67%) ⬆️
src/element/reader.rs 93.58% <ø> (ø)
src/element/sexp.rs 74.19% <ø> (ø)
src/element/writer.rs 92.45% <ø> (ø)
src/lib.rs 89.21% <ø> (+0.37%) ⬆️
src/types/coefficient.rs 91.75% <ø> (ø)
src/types/timestamp.rs 93.33% <87.50%> (+0.52%) ⬆️
src/ion_data/ion_ord.rs 97.72% <97.72%> (ø)
src/element/mod.rs 91.63% <98.46%> (+0.44%) ⬆️
... and 11 more

Help us with your feedback. Take ten seconds to tell us how you rate us. Have a feature suggestion? Share it here.

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

src/element/mod.rs Show resolved Hide resolved
src/element/mod.rs Outdated Show resolved Hide resolved
src/ion_data/mod.rs Outdated Show resolved Hide resolved
src/ion_data/mod.rs Outdated Show resolved Hide resolved
src/ion_data/mod.rs Outdated Show resolved Hide resolved
src/lib.rs Outdated Show resolved Hide resolved
src/lib.rs Outdated Show resolved Hide resolved
src/ion_data/ion_ord.rs Outdated Show resolved Hide resolved
@popematt popematt requested a review from almann April 21, 2023 21:30
@popematt
Copy link
Contributor Author

@almann or @zslayton, can you recommend any good idioms for making this also work nicely with borrowed values (i.e. &Element)?

Copy link
Contributor

@almann almann left a comment

Choose a reason for hiding this comment

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

:shipit: A couple questions below, but overall I am good.

src/ion_data/mod.rs Outdated Show resolved Hide resolved
src/ion_data/mod.rs Outdated Show resolved Hide resolved
Comment on lines +44 to +67
impl<T: IonEq> From<T> for IonData<T> {
fn from(value: T) -> Self {
IonData(value)
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@almann, it's here.

Copy link
Contributor

@almann almann left a comment

Choose a reason for hiding this comment

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

🚢 LGTM!

src/ion_data/mod.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@zslayton zslayton left a comment

Choose a reason for hiding this comment

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

LGTM, but one request regarding doc comments below.

src/ion_data/mod.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@almann almann left a comment

Choose a reason for hiding this comment

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

Overall, I am happy with where this is going, however I am a bit puzzled by the added Bool/Float wrappers. I think if this is needed to hide IonEq we may want to reconsider doing this.

(Int(this), Int(that)) => this.ion_eq(that),
(Float(this), Float(that)) => this.ion_eq(that),
(Float(this), Float(that)) => float::Float::ion_eq_f64(this, that),
Copy link
Contributor

Choose a reason for hiding this comment

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

This is curious, probably worth a comment indicating why this is needed.

src/ion_data/ion_eq.rs Outdated Show resolved Hide resolved
impl IonEq for bool {
impl<R: Deref> IonEq for R
where
<R as Deref>::Target: IonEq,
Copy link
Contributor

Choose a reason for hiding this comment

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

I have a slight preference for this kind of formulation, but this is totally subjective.

impl<E, R> IonEq for R where
  E: IonEq,
  R: Deref<Target = E>,

Copy link
Contributor Author

@popematt popematt Apr 25, 2023

Choose a reason for hiding this comment

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

Actually, there is a difference here, and it causes an error when I change it. Here's a minimum reproducible case:

// Assuming we're using
// impl<E, R> IonEq for R where E: IonEq, R: Deref<Target = E> { ... }

#[test]
fn foo() {
    let element_vec: Vec<Element> = Element::read_all("foo 1 true").unwrap();
    bar(element_vec.into());
}

fn bar<T: IonEq>(ion: IonData<T>) {
    // Do something
}

Fails with:

error[E0277]: the size for values of type `[element::Element]` cannot be known at compilation time

I'm assuming that this is because the trait impl is monomorphized differently depending on how the signature is formulated. (While rearranging a where clause shouldn't do something like this, in this case we have added a second type parameter and we have changed how Deref::Target is specified.)

Do you have any insight or theory on the details of why this occurs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Aha... it needs ?Sized:

impl<E, R> IonEq for R where
  E: IonEq + ?Sized,
  R: Deref<Target = E>,

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 ended up sticking with my original factoring because it minimizes the number of type parameters, though I cleaned it up by getting rid of some redundant parts.

impl<R: Deref> IonEq for R
where
    R::Target: IonEq,

}
// For all other values, fall back to mathematical equivalence
self == other
<Self as Deref>::Target::ion_eq(self, other)
Copy link
Contributor

Choose a reason for hiding this comment

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

With my above declaration I think you can write this as:

E::ion_eq(self, other)

Comment on lines 14 to 19
impl<R: Deref> IonOrd for R
where
<R as Deref>::Target: IonOrd,
{
fn ion_cmp(&self, other: &Self) -> Ordering {
T::ion_cmp(self, other)
<Self as Deref>::Target::ion_cmp(self, other)
Copy link
Contributor

Choose a reason for hiding this comment

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

Ditto for above.

src/types/bool.rs Outdated Show resolved Hide resolved
src/types/float.rs Outdated Show resolved Hide resolved
@popematt
Copy link
Contributor Author

Hopefully this is good to go now. Latest commit includes:

  • Remove Float and Bool in favor of just using ion_eq_f64(), etc. functions with a detailed note about why the functions exist.
  • Remove someAsRef impls that this PR added that weren't actually needed.
  • Minor clarifications, cleanups.

@popematt popematt requested a review from almann April 25, 2023 23:05
Copy link
Contributor

@almann almann left a comment

Choose a reason for hiding this comment

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

:shipit: LGTM

@popematt popematt merged commit f69a0eb into amazon-ion:main Apr 25, 2023
6 checks passed
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.

None yet

3 participants