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

Makes UInt an opaque struct type #568

Merged
merged 3 commits into from
Jun 15, 2023
Merged

Makes UInt an opaque struct type #568

merged 3 commits into from
Jun 15, 2023

Conversation

zslayton
Copy link
Contributor

@zslayton zslayton commented Jun 15, 2023

Prior to this patch, UInt was an enum offering two storage
options: u64 and BigUint.

This patch wraps that enum (now a private type called UIntData) in
an opaque struct, giving us the ability to change that representation
in the future without a breaking change.

This also provides a TryFrom<&UInt> implementation for all primitive
integer types.

Related to #507.

A follow-on PR will make the same change for the signed Int type.

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

Zack Slayton added 2 commits June 15, 2023 15:14
Prior to this patch, `UInt` was an enum offering two storage
options: `u64` and `BigUInt`.

This patch wraps that enum (now a private type called `UIntData`) in
an opaque struct, giving us the ability to change that representation
in the future without a breaking change.
Copy link
Contributor Author

@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.

🗺️ PR tour

Comment on lines +22 to +24
magnitude: UInt {
data: UIntData::U64(0),
},
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️ magnitude: 064.into() would be more concise, but the trait method into() is not const.

Comment on lines +75 to +77
let mut coefficient_bytes = match &decimal.coefficient.magnitude().data {
UIntData::U64(unsigned) => unsigned.to_be_bytes().into(),
UIntData::BigUInt(big) => big.to_bytes_be(),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️ This diff contains several instances of this change. Instead of matching directly on the UInt, we now match on its private inner UIntData field.

@@ -689,7 +690,7 @@ mod tests {
let mut buffer = BinaryBuffer::new(&[0b1000_0000]);
let var_int = buffer.read_uint(buffer.remaining())?;
assert_eq!(var_int.size_in_bytes(), 1);
assert_eq!(var_int.value(), &UInt::U64(128));
assert_eq!(var_int.value(), &UInt::from(128));
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 used TypeName::from instead of value.into() in several places because that's the only way to specify the expected type inline. You can't use turbofish syntax with Into.

Comment on lines +66 to 74
pub struct UInt {
pub(crate) data: UIntData,
}

#[derive(Debug, Clone)]
pub(crate) enum UIntData {
U64(u64),
BigUInt(BigUint),
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️ This is the core change; the rest of the diff is comprised of ripples.

)*)
}

impl_int_types_from_uint!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️ Previously, we only provided a TryFrom<&UInt> implementation for usize and i64. That was more or less acceptable because UInt wasn't part of the public API. However, I think it needs to be in a couple of places. For example, a Decimal::coefficient method.

Comment on lines -255 to -292
impl TryFrom<&UInt> for i64 {
type Error = IonError;

fn try_from(value: &UInt) -> Result<Self, Self::Error> {
match value {
UInt::U64(uint) => i64::try_from(*uint).or_else(|_| {
decoding_error(format!(
"Unsigned integer {uint:?} was too large to be represented as an i64."
))
}),
UInt::BigUInt(big_uint) => i64::try_from(big_uint).or_else(|_| {
decoding_error(format!(
"Unsigned integer {big_uint:?} was too large to be represented as an i64."
))
}),
}
}
}

impl TryFrom<&UInt> for usize {
type Error = IonError;

fn try_from(value: &UInt) -> Result<Self, Self::Error> {
match value {
UInt::U64(uint) => usize::try_from(*uint).or_else(|_| {
decoding_error(format!(
"Unsigned integer {uint:?} was too large to be represented as an usize."
))
}),
UInt::BigUInt(big_uint) => usize::try_from(big_uint).or_else(|_| {
decoding_error(format!(
"Unsigned integer {big_uint:?} was too large to be represented as an usize."
))
}),
}
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️ These manual implementations of TryFrom have been supplanted by the macro we just saw above.

@zslayton zslayton requested a review from popematt June 15, 2023 20:47
@zslayton zslayton marked this pull request as ready for review June 15, 2023 20:48
@zslayton zslayton merged commit 4f3724b into main Jun 15, 2023
18 of 19 checks passed
@zslayton zslayton deleted the opaque-uint branch June 15, 2023 21:22
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

2 participants