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

Implements Geometry::make_valid. #356

Merged
merged 4 commits into from
Jan 10, 2023
Merged

Conversation

metasim
Copy link
Contributor

@metasim metasim commented Dec 31, 2022

  • I agree to follow the project's code of conduct.
  • I added an entry to CHANGES.md if knowledge of this change could be valuable to users.

Partially addresses #306.

cc: @thomas001

CHANGES.md Outdated Show resolved Hide resolved
src/vector/geometry.rs Outdated Show resolved Hide resolved
@metasim metasim force-pushed the feature/geom-mkvalid branch from 9d81e62 to 719be8b Compare December 31, 2022 17:47
src/vector/geometry.rs Outdated Show resolved Hide resolved
src/vector/geometry.rs Outdated Show resolved Hide resolved
@metasim metasim force-pushed the feature/geom-mkvalid branch 8 times, most recently from 0422ceb to bced706 Compare January 2, 2023 21:11
@metasim metasim force-pushed the feature/geom-mkvalid branch from 8b91a97 to 8da2c75 Compare January 8, 2023 19:42
@metasim metasim marked this pull request as ready for review January 8, 2023 19:43
@metasim metasim requested a review from lnicola January 8, 2023 19:45
fn from(pairs: &[(&str, &str); N]) -> Self {
let mut result = Self::default();
for (k, v) in pairs {
result.set_name_value(k, v).expect("valid key/value pair");
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
result.set_name_value(k, v).expect("valid key/value pair");
result.set_name_value(k, v).expect("invalid key/value pair");

I think the message would be something like valid key/value pair: "Invalid characters in name: '#'", which doesn't make sense.

And going back a little, I'm not sure what to say about this impl. from should be infallible, so try_from would be better, which this clearly isn't. On the other hand, it's probably going to be used with compile-constant keys and values. Is that why you've implemented it for fixed-size arrays (as opposed to &[(&str, &str)])?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Is that why you've implemented it for fixed-size arrays

No. More of a result of me playing type golf; Without the const parameter I get this error. Probably me being dumb.

image

The fact that set_name_value is fallible is really annoying, but understandable. Going with try_from pretty much eliminates the benefits of having this. So if you're in doubt about it, I think I should just remove it all together.

Copy link
Member

Choose a reason for hiding this comment

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

Oof, yes, I think you need to cast it, like in https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=0c8e96e6b31a1d7ac28a76cce7abbd1b. Anyway, I suppose it's fine.

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 think the message would be something like valid key/value pair: "Invalid characters in name: '#'", which doesn't make sense.

Are you 100% sure? (I'm not) 😄

Per the docs

We recommend that expect messages are used to describe the reason you expect the Result should be Ok.

Copy link
Member

Choose a reason for hiding this comment

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

Can you test? 😀 I can't right now, sorry.

My reading of the docs is something like CslStringList::try_from(&["FOO", "BAR"]).expect("obviously correct"), that is, user code. It's different in library code which can and will actually panic.

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 not sure I'm following your line of thinking here. Happy to submit a new PR revisiting this.

Copy link
Member

Choose a reason for hiding this comment

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

Indeed, this produces:

thread 'cpl::tests::from_impl' panicked at 'valid key/value pair: BadArgument("Invalid characters in name: 'TWO#'")', src/cpl.rs:204:41

compared to a random example from libcore:

self.checked_add(rhs).expect("overflow when adding durations")

src/vector/geometry.rs Outdated Show resolved Hide resolved

#[test]
#[allow(clippy::float_cmp)]
pub fn test_area() {
let _nolog = SuppressGDALErrorLog::new();
Copy link
Member

@lnicola lnicola Jan 10, 2023

Choose a reason for hiding this comment

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

I'm not sure we should hide these GDAL warnings, especially given that the tests are run on multiple threads. GDAL doesn't synchronize accesses to that list (not that it makes sense to use it from multiple threads), so there's a chance we'll corrupt its handler stack.

Copy link
Contributor Author

@metasim metasim Jan 10, 2023

Choose a reason for hiding this comment

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

I only put these in in tests that are supposed to generate errors. e.g.

layer.set_attribute_filter("foo = bar").unwrap_err(),

According to the API docs the approach I used should be thread safe.

This pushes a new error handler on the thread-local error handler stack. This handler will be used until removed with CPLPopErrorHandler().

My reasoning behind this utility was to make life easier when going through test logs when there is a failure. We have a bunch of stay messages that look like something went wrong when the error condition was expected. I really don't like logs that have false error messages in them. IMO, in good Unix style, successes should be quiet.

Copy link
Member

Choose a reason for hiding this comment

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

Ah, I missed it being thread-local. Should be fine, then 👍.

@@ -251,7 +251,8 @@ pub trait LayerAccess: Sized {
}

/// Set a feature on this layer layer.
/// Refer[SetFeature](https://gdal.org/doxygen/classOGRLayer.html#a681139bfd585b74d7218e51a32144283)
///
/// Refer [SetFeature](https://gdal.org/doxygen/classOGRLayer.html#a681139bfd585b74d7218e51a32144283)
Copy link
Member

Choose a reason for hiding this comment

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

Consistency nit: below it says Refer: , maybe See would sound better.

Copy link
Contributor Author

@metasim metasim Jan 10, 2023

Choose a reason for hiding this comment

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

I don't like Refer either... but was trying to be consistent (but forgot the colon here). I'll update.

Copy link
Member

@lnicola lnicola left a comment

Choose a reason for hiding this comment

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

The error handling changes seem like a really bad idea.

I'm also unsure about the From implementation for CslStringList, but that's probably less important. From (sic!) the docs:

Note: This trait must not fail. The From trait is intended for perfect conversions. If the conversion can fail or is not perfect, use TryFrom.

Other than that, LGTM.

Co-authored-by: Laurențiu Nicola <[email protected]>
@metasim
Copy link
Contributor Author

metasim commented Jan 10, 2023

The error handling changes seem like a really bad idea.

I detailed my rationale here. Only doing it because a) I believe successful tests should not report error messages, and b) according to the gdal docs, the implementation should be thread-safe.

@metasim
Copy link
Contributor Author

metasim commented Jan 10, 2023

I'm also unsure about the From implementation for CslStringList, but that's probably less important.

I'm also unsure about this. Maybe I should just drop this impl until we figure out a more ergonomic way to construct static CslStringLists?


#[test]
#[allow(clippy::float_cmp)]
pub fn test_area() {
let _nolog = SuppressGDALErrorLog::new();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Without this specific suppression, the log message is

Warning 1: OGR_G_Area() called against non-surface geometry type.

@lnicola
Copy link
Member

lnicola commented Jan 10, 2023

We could also implement TryFrom, which seems like a good thing to have anyway.

bors d+

@bors
Copy link
Contributor

bors bot commented Jan 10, 2023

✌️ metasim can now approve this pull request. To approve and merge a pull request, simply reply with bors r+. More detailed instructions are available here.

@metasim
Copy link
Contributor Author

metasim commented Jan 10, 2023

bors r+

@metasim
Copy link
Contributor Author

metasim commented Jan 10, 2023

@lnicola Thanks for slogging through this with me! I'm really happy with the result. Wouldn't be half as good without your feedback! 😃

@bors bors bot merged commit 1f55546 into georust:master Jan 10, 2023
@metasim metasim deleted the feature/geom-mkvalid branch January 10, 2023 19:50
@metasim metasim mentioned this pull request May 18, 2023
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.

3 participants