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 IonSchemaElement use borrowed Elements #222

Merged
merged 2 commits into from
Oct 15, 2024

Conversation

popematt
Copy link
Contributor

Issue #, if available:

Fixes #214
Fixes #137

Description of changes:

Changes IonSchemaElement so that it holds references to Elements rather than owning Elements. Details in PR tour 🗺️ comments.


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

@popematt popematt force-pushed the borrow-elements branch 2 times, most recently from 63cb7fc to 32a6cf5 Compare October 14, 2024 19:04
Makes IonSchemaElement use borrowed Elements
Comment on lines +324 to +326
let schema = __new_schema_system().load_schema(schema_id).expect(&format!("Expected to load schema: {}", schema_id));
let isl_type = schema.get_type(type_id).expect(&format!("Expected to get type: {}", type_id));
let value: ion_rs::Element = ion_rs::Element::read_one(value_ion.as_bytes()).expect(&format!("Expected to be able to read value: {}", value_ion));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️ Drive-by improvement to get better failure messages in the test runner.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not very familiar with this part of the code--it looks like this is a method that only gets run in testing, so performance may not matter. If so, you can disregard.

These expect(&format!(...)) calls will allocate/format a String even if the previous method calls succeed. We should use something like Result::unwrap_or_else(|| panic!("Expected ...")) to sidestep the cost on the happy path.

https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or_else

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's only in testing.

"imports",
"constraints::ordered_elements",
"constraints::precision",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️ It turns out that we don't need to skip the tests for precision any more. However, the fix was in some previous change. All of the other changes in this file are just trying to improve the specificity of the comments.

@@ -93,125 +92,6 @@ const ISL_2_0_KEYWORDS: [&str; 28] = [
"valid_values",
];

/// Provide an Ion schema Element which includes all Elements and a document type
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️ All of this was moved to ion_schema_element.rs (and then rewritten).

@@ -156,8 +155,11 @@ impl NfaEvaluation {
}

/// Validates provided ordered elements against referenced [Nfa]
pub fn validate_ordered_elements(&mut self, elements: &[Element], type_store: &TypeStore) {
let mut elements_iter = elements.iter().peekable();
pub fn validate_ordered_elements<'a, T: Iterator<Item = &'a Element>>(
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️ The NFA implementation now accepts any iterator over Elements, rather than requiring a slice of Elements or being tied to a particular iterator implementation.

Comment on lines -447 to -449
// this is just a place holder for document type,
// IonSchemaElement::Document(_) type is used to verify the correctness on the validation side
"type::{ name: document }",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

🗺️ document is an "atomic" type instead of a "derived" type now that we have IonSchemaElementType::Document.

@popematt popematt marked this pull request as ready for review October 14, 2024 19:50
Comment on lines +324 to +326
let schema = __new_schema_system().load_schema(schema_id).expect(&format!("Expected to load schema: {}", schema_id));
let isl_type = schema.get_type(type_id).expect(&format!("Expected to get type: {}", type_id));
let value: ion_rs::Element = ion_rs::Element::read_one(value_ion.as_bytes()).expect(&format!("Expected to be able to read value: {}", value_ion));
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not very familiar with this part of the code--it looks like this is a method that only gets run in testing, so performance may not matter. If so, you can disregard.

These expect(&format!(...)) calls will allocate/format a String even if the previous method calls succeed. We should use something like Result::unwrap_or_else(|| panic!("Expected ...")) to sidestep the cost on the happy path.

https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or_else

@@ -321,18 +321,15 @@ fn generate_preamble(root_dir_path: &Path) -> TokenStream {

/// Asserts that a value is or is not valid for a given ISL type.
fn __assert_value_validity_for_type(value_ion: &str, schema_id: &str, type_id: &str, expect_valid: bool) -> Result<(), String> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you happen to know why we're using a __ prefix rather than, say, making a new submodule to house these functions?

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 wanted to make sure that we didn't have any name conflicts with a generated test case, so I added a __ prefix. I could have added a new submodule, but that probably also would have needed something to reduce the likelihood of a name conflict with a generated test function.

let mut elements_iter = elements.iter().peekable();
pub fn validate_ordered_elements<'a, T: Iterator<Item = &'a Element>>(
&mut self,
mut elements_iter: Peekable<T>,
Copy link
Contributor

Choose a reason for hiding this comment

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

TIL that Peekable's impl of peekable() is not specialized to avoid producing a Peekable<Peekable<T>>.

@@ -267,12 +269,12 @@ impl NfaEvaluation {
// this method iterates through elements to satisfy minimum required occurrences for given transition
// It will return false if an invalid Ion value is found which doesn't satisfy minimum occurrence requirement for given transition
// Otherwise it will return true
fn evaluate_transition_to_self(
fn evaluate_transition_to_self<'a, T: Iterator<Item = &'a Element>>(
Copy link
Contributor

Choose a reason for hiding this comment

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

Food for thought: you could create a new trait for this to avoid having to spell out the bounds each time.

// Make an empty extension trait called `ElementIter`...
trait ElementIter<'a>: Iterator<Item = &'a Element> {}
impl<'a, T> ElementIter<'a> for T where T: Iterator<Item = &'a Element> {}

// ...and then replace this:
fn evaluate_transition_to_self<'a, T: Iterator<Item = &'a Element>> (...) {...}

// ...with this:
fn evaluate_transition_to_self<'a, T: ElementIter<'a>>(...) {...}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I guess I could. TBH, though, I'm hoping to do a fairly complete rewrite the NFA to get better error messages like in amazon-ion/ion-schema-kotlin#228

@popematt popematt merged commit 4b27d7f into amazon-ion:main Oct 15, 2024
3 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.

Validate API should borrow the data it is validating ion_schema should not re-export ion_rs
2 participants