-
Notifications
You must be signed in to change notification settings - Fork 34
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 IonError
variants wrap opaque types
#584
Conversation
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## main #584 +/- ##
==========================================
- Coverage 83.30% 83.18% -0.13%
==========================================
Files 104 110 +6
Lines 19705 19764 +59
Branches 19705 19764 +59
==========================================
+ Hits 16416 16441 +25
- Misses 1739 1765 +26
- Partials 1550 1558 +8
☔ View full report in Codecov by Sentry. |
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.
🗺️ PR tour
src/binary/decimal.rs
Outdated
@@ -10,10 +10,9 @@ use crate::binary::raw_binary_writer::MAX_INLINE_LENGTH; | |||
use crate::binary::var_int::VarInt; | |||
use crate::binary::var_uint::VarUInt; | |||
use crate::ion_data::IonEq; | |||
use crate::result::IonResult; | |||
use crate::result::{encoding_error_raw, IonResult}; |
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 TODO
to limit the visibility of types to a single prescribed path within the crate. For the moment, IonResult
can be found in both the crate root (crate::IonResult
) and in result
(crate::result::IonResult
). This is true of other types as well.
// TODO: IonResult should have a distinct `IncompleteData` error case | ||
// https://github.com/amazon-ion/ion-rust/issues/299 | ||
{ | ||
decoding_error("Unexpected end of stream.") | ||
} | ||
Err(io_error) => Err(IonError::IoError { source: io_error }), | ||
Err(io_error) => Err(io_error.into()), |
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.
🗺️ The new opaque struct error types (defined further down) can implement traits like Into
, making for nicer code.
@@ -261,9 +261,8 @@ mod tests { | |||
} | |||
} | |||
|
|||
/// Types that implement this trait can be converted into an implementation of [io::BufRead], | |||
/// allowing users to build a [Reader](crate::reader::Reader) from a variety of types that might not |
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.
🗺️ This doc comment referred to Reader
, which is feature gated. If you attempted to build the docs without "experimental-reader"
enabled, it would fail because Reader
was not public.
/// maximize encoding efficiency. To reuse a writer and have greater control over resource | ||
/// management, see [`Element::write_to`]. |
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.
🗺️ This doc comment referred to Element::write_to
, which is feature gated. If you attempted to build the docs without "experimental-writer"
enabled, it would fail because write_to
was not available.
This change hides that sentence when write_to
is not available. The content of the comment is otherwise unchanged.
@@ -663,66 +670,82 @@ impl Element { | |||
} | |||
} | |||
|
|||
/// Serializes this [`Element`] as binary Ion, returning the output as a `Vec<u8>`. | |||
/// | |||
/// This is a convenience method; it is less efficient than [`Element::write_to`] because: |
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.
🗺️ This doc comment referred to write_to
, which is feature gated. If you attempted to build the docs without "experimental-writer"
enabled, it would fail because write_to
was not available.
This change hides that section when write_to
is not available. The content of the comment is otherwise unchanged.
Err(IonError::Incomplete { | ||
position: | ||
Position { | ||
line_column: Some((line, column)), | ||
.. | ||
}, | ||
.. | ||
}) => { | ||
assert_eq!(line, 2); | ||
assert_eq!(column, 0); | ||
Err(IonError::Incomplete(e)) => { | ||
assert_eq!(e.position().line(), Some(2)); | ||
assert_eq!(e.position().column(), Some(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.
🗺️ This is a good example of the updated application code for inspecting an IonError
that has cropped up.
@@ -371,16 +376,17 @@ impl TryFrom<f64> for Decimal { | |||
|
|||
fn try_convert(coefficient: f64, exponent: i64) -> Result<Decimal, IonError> { | |||
// prefer a compact representation for the coefficient; fallback to bigint | |||
let coefficient: Coefficient = if !coefficient.trunc().is_zero() |
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.
🗺️ This section is a formatting-only change.
})?; | ||
if self.precision == Precision::Month { | ||
return Ok(datetime); | ||
} | ||
|
||
// If precision >= Day, the day must be set. | ||
let day = self.day.expect("missing day"); | ||
datetime = datetime |
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.
🗺️ This section is a formatting-only change.
@@ -119,7 +120,7 @@ fn ion_hash_tests() -> IonHashTestResult<()> { | |||
} | |||
|
|||
fn test_file(file_name: &str) -> IonHashTestResult<()> { | |||
let data = read(file_name).map_err(|source| ion_rs::IonError::IoError { source })?; | |||
let data = read(file_name).map_err(IonError::from)?; |
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.
🗺️ Another example of trait impls making the code a bit nicer.
@@ -224,7 +225,7 @@ fn expected_hash(struct_: &Struct) -> IonResult<Vec<u8>> { | |||
let identity = if let Some(identity) = struct_.get("identity") { | |||
identity.as_sequence().expect("`identity` should be a sexp") | |||
} else { | |||
illegal_operation("only identity tests are implemented")? | |||
todo!("only identity tests are implemented") |
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.
🗺️ ion-hash-tests was constructing its own IonResult
s to describe failure modes that didn't come from Ion itself. The error constructor methods are now limited to crate-visibility. Clients like ion-hash-tests should use their own error type.
In ion-hash-tests' case, it was bubbling up the error result and panicking later on. I've changed those failures to an immediate panic. The end result is the same, and it removes the dependency on now-private functionality.
src/result/decoding_error.rs
Outdated
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.
🗺️ We still need to add doc comments for these new types. I have opened #589 to track that.
return illegal_operation(format!( | ||
return IonResult::illegal_operation(format!( |
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.
Good change!
return IonResult::illegal_operation( | ||
"Values inside a struct must have a field name.", | ||
); |
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.
Generally speaking an error message without context is less helpful than one that does have context. It might be helpful to provide some indication here of which value does not have a field name. I'm not suggesting that we fix it in this PR, but what sort of additional book-keeping or capabilities might we need to provide context in cases like this?
I created #590 to track/discuss.
Perhaps it would be good to link to #590 in places like this, so that it's easier to come back to later?
On the other hand, if we had a more universal context description ability then we'd likely do some general pass when the capability was added.
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.
Agreed on all counts. (This particular case is a bit of an outlier--it shouldn't happen since it's serializing a fully-formed Element
. Not setting a field name would be user error when driving an IonWriter
.)
src/result/mod.rs
Outdated
// Crate-visible convenience methods for constructing error variants and wrapping them in the | ||
// appropriate type: IonResult<T> or IonError. This is a trait so these methods can be added to | ||
// `IonResult<T>`, which is just a type alias for `Result<T, IonError>`, whose implementation | ||
// does not live in this crate. | ||
pub(crate) trait IonFailure { | ||
fn incomplete(label: &'static str, position: impl Into<Position>) -> Self; | ||
fn decoding_error<S: Into<String>>(description: S) -> Self; | ||
fn encoding_error<S: Into<String>>(description: S) -> Self; | ||
fn illegal_operation<S: Into<String>>(operation: S) -> Self; | ||
} |
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.
It does not include an
io
method because the only way we ever constructIonError::Io
is by converting astd::io::IoError
with the?
operator.
Could this stand to be a comment?
This PR refactors the
IonError
enum variants to each wrap an opaque struct type. The wrapped types each offer methods and trait implementations that we can expand upon in the future without breaking changes.By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.