Repository navigation
Conversation
|
@tombieli Thanks for the PR! Would you be willing to document the methods you added? Here are some examples of what we're looking for: https://github.com/georust/gdal/blob/master/src/vector/ops/transformations.rs |
@metasim: |
metasim
left a comment
There was a problem hiding this comment.
Would also like to get a review from one of the other maintainers.
Co-authored-by: Simeon H.K. Fitch <fitch@astraea.io>
|
@metasim: |
|
Hello @lnicola, |
|
Thanks, I'll take a look in a bit. |
|
|
||
| /// Get spheroid semi-major axis. | ||
| /// | ||
| /// Returns [`Err`] variant in case the C library returns an error code different from [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE). |
There was a problem hiding this comment.
To be honest, I'm not really a fan of these, since they basically say "the function returns Err if the C function returned an error", which is true, but useless.
But I don't mind them too much, so it's all right if you like them.
There was a problem hiding this comment.
I maybe tried to be to precise and I created to explicit documentation.
There was a problem hiding this comment.
Docs are good, but this is currently neither consistent with the rest of the documentation, nor useful: "the function returns Err if an error has occurred" doesn't bring any information at all to someone used to the Rust conventions.
Looking at GetSemiMajor, it's a bit weird -- it returns both a valid value (SRS_WGS84_SEMIMAJOR) and an error if it can't find the value, which is something I'm not sure we want to emulate.
Can you change this to something like "Returns an error if the semi-major axis can't be found" ("semi-minor" for the other one), "if there the PROJCS node is missing" for set_proj_param?
GetProjParm returns an error if it can't find PROJCS or CONVERSION, or if the parameter is missing. OSRSetAttrValue returns an error if the path is empty. OSRGetAttrValue returns an error if the attribute can't be found.
For geog_cs, it's a bit complicated, I guess an error means that it's missing.
These expose some of the GDAL internals, but I don't expect them to change significantly.
Also, OSRSetAttrValue in GDAL can take a null value, which means that the node is created without a value. Maybe we should take an Option<&str> to support that?
There was a problem hiding this comment.
@lnicola:
I've corrected comments.
I've also decided to change signature of get_proj_param to:
pub fn get_proj_param(&self, name: &str) -> Result<Option<f64>>I did not include a default value option, because in each case this value will be discarded.
I've done similar thing to get_attr_value.
There is also problem with set_attr_value. I've tried to write some tests which set some silly (like "Spam" or "Eggs") and less silly (like "WGS_1984" and "metre") data, but results were quite strange. I'm not an expert at manipulation of WKT for projection, so I maybe tried to write tests in wrong way. Maybe some of You will have better idea how to write those tests.
Alternatively we can remove this function now and implement it later.
There was a problem hiding this comment.
but results were quite strange
You're right, I'll try to look into it.
There was a problem hiding this comment.
I took the liberty of pushing a commit to fix this and add a test. It was a pretty basic gotcha -- Option::map consumes the value. I would have hoped that clippy would catch this, but alas...
There was a problem hiding this comment.
Thanks. Rust/C++ edge can be tricky.
There was a problem hiding this comment.
Everything can be tricky. The Python bindings will segfault if you do something similar with a SpatialRef, so it's not just us.
| /// Returns [`Err`] variant in case the C library returns an error code different from [`OGRERR_NONE`](https://gdal.org/api/vector_c_api.html#c.OGRERR_NONE). | ||
| /// | ||
| /// See: [`OSRGetProjParm`](https://gdal.org/api/ogr_srs_api.html#_CPPv414OSRGetProjParm20OGRSpatialReferenceHPKcdP6OGRErr) | ||
| pub fn get_proj_param(&self, name: &str) -> Result<f64> { |
There was a problem hiding this comment.
So ideally, this would return something like Result<Option<f64>> and the user could handle the missing case. But since we can't do that, should we take the default as an argument? Just noticed the other method, should we drop this one and rename?
It's currently ambiguous. Are the parameters never 0 in practice?
There was a problem hiding this comment.
Behavior of OSRGetProjParm is quite tricky, a least from Rust point of view.
In C and C++ if value is found it is returned normally, but if value is not found, a value from default parameter is returned, but also error code (if pointer is not null) is set to OGRERR_FAILURE. However looking from Rust point of view it may mean not found (therefore is candidate for Option::None) or can mean any other failure.
You can see this in GDAL source code for OSRGetProjParm.
To sum up:
- on existing value: we receive the value itself,
- if value does not exist: we receive default value and very general error code.
That's why I used only Result<f64> as return type and I also created also get_proj_param_or_default.
There was a problem hiding this comment.
Yeah, I'm inclined towards something like a single pub fn get_proj_param(&self, name: &str) -> Result<Option<f64>>, which returns Err on a string conversion error (basically never), and Ok(None) on OGRERR_FAILURE. It's not that awkward to use, and should be pretty clear.
Both error cases in the implementation are similar, and boil down to "there's no parameter with that name on the PROJCS".
EDIT: removed the default param.
There was a problem hiding this comment.
Yeah, this is all unfortunate legacy API leakage. I don't know what we should do, or if there are other examples out there (e.g. proj?) but what if we had a new error type defined that indicates NotSet? Then, you clould go back to returning Result<f64> and users who care about a default can match on Err(NotSet) to handle it?
…usize. Following suggestion from @lnicola.
…tr_value and releveant tests. Based on suggestions by @lnicola.
|
Added one more commit with an r? @jdroenner, otherwise I'll r+ tomorrow or so. |
@lnicola: |
|
@tombieli first of all, my bad, I shouldn't have pushed this commit, but rather left it as a review comment. I only did it because I felt bad for letting this PR linger for so long, and wanted to get the new release out of the gate soon. And I actually mentioned it in the same comment where I suggested using That said, to address your points:
The C++ code doesn't handle this properly, because the issue is in the Rust wrapper. C++ takes
That feels like sweeping the problem -- which we introduced, by taking So the question is whether to panic or return an error. My reasoning is that the caller must have gotten the index from somewhere. As far as I can tell, there are three ways one could get it:
So I don't see any way code that's not hopelessly broken could end up with such a large index there. And I think in Rust it's rather common to panic in such cases, instead of allowing the program to keep running, only to crash or fail in a more obscure way later on. But if we do decide to keep the panic, we should document it just in case. |
|
@lnicola: Thank You for Your answer. I questioned this move with
But looking from other side: I see on this simple example, that mapping API to Rust from C++ could be very tricky, especially when C++ library has its own non-rust ideas to create function contract (for instance: using signed integer for non-negative values and three-state result/error reporting). I understand that chances to fire that I don't have big experience in Rust, and no experience in shipping production code in Rust. I know that having theoretical bright ideas is not enough, so I don't expect that my opinion on this topic is 100% accurate (it may even less than 50% ;) ). If You as maintainer want this
I will add relevant info in docs. |
I'm not the only maintainer, and even if I were, it wasn't a nice thing to do.
I understand that viewpoint, but i think even the standard library will panic at times, for example when it detects that an invariant of a data structure got broken. One pattern I've seen time and time again (especially in other languages) was:
So I'm firmly in the "crash early if the caller is hopelessly buggy" camp, since limping on with some corrupted state will be much harder to detect. And I've tried to show earlier that there's no way a caller could pass a value larger than But as I said, I'm not the only maintainer. It might be interesting to see other opinions on this. |
|
I think the solution with the assert! is fine. I guess we can't avoid it in some cases... |
|
Can you rebase (or merge) to fix the conflict? |
Yes. Merge commit is in the branch. |
|
bors r=metasim,lnicola |
|
Build succeeded! The publicly hosted instance of bors-ng is deprecated and will go away soon. If you want to self-host your own instance, instructions are here. If you want to switch to GitHub's built-in merge queue, visit their help page. |
CHANGES.mdif knowledge of this change could be valuable to users.Hello,
I wrote additional methods for
SpatialRefto access some properties fromOGRSpatialReference.I needed those properties in project which I'm prototyping :) .
Of course I've added also relevant tests.
Best Regards,
Tomasz Bieliński