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

Make PjInfo struct public #133

Merged
merged 14 commits into from
Jun 23, 2022
3 changes: 3 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Changes

## Unreleased
- Inline the functionality of the legacy `Info` trait directly into `Proj`/`ProjBuilder` and remove the `Info` trait.
- Make `PjInfo` struct public, and rename it to `Info`
urschrei marked this conversation as resolved.
Show resolved Hide resolved
- <https://github.com/georust/proj/pull/133>
- Actually return an error if a definition can't be retrieved
- <https://github.com/georust/proj/pull/132>

Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -249,4 +249,4 @@ pub use crate::proj::Proj;
pub use crate::proj::ProjBuilder;
pub use crate::proj::ProjCreateError;
pub use crate::proj::ProjError;
pub use crate::proj::Projinfo;
pub use crate::proj::ProjInfo;
133 changes: 72 additions & 61 deletions src/proj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,54 +227,57 @@ fn transform_epsg(
})
}

/// Read-only utility methods for providing information about the current PROJ instance
pub trait Info {
#[doc(hidden)]
fn ctx(&self) -> *mut PJ_CONTEXT;

/// Return [Information](https://proj.org/development/reference/datatypes.html#c.PJ_INFO) about the current PROJ context
/// # Safety
/// This method contains unsafe code.
fn info(&self) -> Result<Projinfo, ProjError> {
unsafe {
let pinfo: PJ_INFO = proj_info();
Ok(Projinfo {
major: pinfo.major,
minor: pinfo.minor,
patch: pinfo.patch,
release: _string(pinfo.release)?,
version: _string(pinfo.version)?,
searchpath: _string(pinfo.searchpath)?,
})
macro_rules! define_info_methods {
() => {
fn ctx(&self) -> *mut PJ_CONTEXT {
self.ctx
}
}

/// Check whether network access for [resource file download](https://proj.org/resource_files.html#where-are-proj-resource-files-looked-for) is currently enabled or disabled.
///
/// # Safety
/// This method contains unsafe code.
fn network_enabled(&self) -> bool {
let res = unsafe { proj_context_is_network_enabled(self.ctx()) };
matches!(res, 1)
}
/// Return information about the current instance of the PROJ libary.
///
/// See: <https://proj.org/development/reference/datatypes.html#c.PJ_INFO>
///
/// If instead you are looking for information about the current projection / conversion, see
/// [`Proj::proj_info`].
///
/// # Safety
/// This method contains unsafe code.
pub fn lib_info(&self) -> Result<Info, ProjError> {
Copy link
Member

@michaelkirk michaelkirk Jun 22, 2022

Choose a reason for hiding this comment

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

I guess this is a breaking change now, but I think it's the right thing to do now that there is another *info method. I also don't expect very many people are actually using it.

Probably worth a new release note though - something like:

BREAKING: Getting information about the version of libproj installed was renamed from proj.info() to proj.lib_info()

unsafe {
let pinfo: PJ_INFO = proj_info();
Ok(Info {
major: pinfo.major,
minor: pinfo.minor,
patch: pinfo.patch,
release: _string(pinfo.release)?,
version: _string(pinfo.version)?,
searchpath: _string(pinfo.searchpath)?,
})
}
}

/// Get the URL endpoint to query for remote grids
///
/// # Safety
/// This method contains unsafe code.
fn get_url_endpoint(&self) -> Result<String, ProjError> {
Ok(unsafe { _string(proj_context_get_url_endpoint(self.ctx()))? })
}
}
/// Check whether network access for [resource file download](https://proj.org/resource_files.html#where-are-proj-resource-files-looked-for) is currently enabled or disabled.
///
/// # Safety
/// This method contains unsafe code.
pub fn network_enabled(&self) -> bool {
let res = unsafe { proj_context_is_network_enabled(self.ctx()) };
matches!(res, 1)
}

impl Info for ProjBuilder {
#[doc(hidden)]
fn ctx(&self) -> *mut PJ_CONTEXT {
self.ctx
}
/// Get the URL endpoint to query for remote grids
///
/// # Safety
/// This method contains unsafe code.
pub fn get_url_endpoint(&self) -> Result<String, ProjError> {
Ok(unsafe { _string(proj_context_get_url_endpoint(self.ctx()))? })
}
};
}

impl ProjBuilder {
define_info_methods!();

/// Enable or disable network access for [resource file download](https://proj.org/resource_files.html#where-are-proj-resource-files-looked-for).
///
/// # Safety
Expand Down Expand Up @@ -310,7 +313,7 @@ impl ProjBuilder {
/// # Safety
/// This method contains unsafe code.
pub fn set_search_paths<P: AsRef<Path>>(&mut self, newpath: P) -> Result<(), ProjError> {
let existing = self.info()?.searchpath;
let existing = self.lib_info()?.searchpath;
let pathsep = if cfg!(windows) { ";" } else { ":" };
let mut individual: Vec<&str> = existing.split(pathsep).collect();
let np = Path::new(newpath.as_ref());
Expand Down Expand Up @@ -354,21 +357,14 @@ impl ProjBuilder {
}
}

impl Info for Proj {
#[doc(hidden)]
fn ctx(&self) -> *mut PJ_CONTEXT {
self.ctx
}
}

enum Transformation {
Projection,
Conversion,
}

/// [Information](https://proj.org/development/reference/datatypes.html#c.PJ_INFO) about PROJ
#[derive(Clone, Debug)]
pub struct Projinfo {
pub struct Info {
pub major: i32,
pub minor: i32,
pub patch: i32,
Expand Down Expand Up @@ -613,6 +609,8 @@ impl Proj {
}
}

define_info_methods!();

/// Returns the area of use of a projection
///
/// When multiple usages are available, the first one will be returned.
Expand Down Expand Up @@ -671,7 +669,16 @@ impl Proj {
}
}

fn pj_info(&self) -> PjInfo {
/// Get information about a specific transformation object.
///
/// See <https://proj.org/development/reference/functions.html#c.proj_pj_info>
///
/// If instead you are looking for information about the PROJ installation, see
/// [`Proj::lib_info`].
///
/// # Safety
/// This method contains unsafe code.
pub fn proj_info(&self) -> ProjInfo {
unsafe {
let pj_info = proj_pj_info(self.c_proj);
let id = if pj_info.id.is_null() {
Expand All @@ -690,7 +697,7 @@ impl Proj {
Some(_string(pj_info.definition).expect("PROJ built an invalid string"))
};
let has_inverse = pj_info.has_inverse == 1;
PjInfo {
ProjInfo {
id,
description,
definition,
Expand All @@ -705,7 +712,7 @@ impl Proj {
/// # Safety
/// This method contains unsafe code.
pub fn def(&self) -> Result<String, ProjError> {
self.pj_info().definition.ok_or(ProjError::Definition)
self.proj_info().definition.ok_or(ProjError::Definition)
}

/// Project geodetic coordinates (in radians) into the projection specified by `definition`
Expand Down Expand Up @@ -1018,17 +1025,21 @@ impl convert::TryFrom<(&str, &str)> for Proj {
}
}

struct PjInfo {
id: Option<String>,
description: Option<String>,
definition: Option<String>,
has_inverse: bool,
accuracy: f64,
/// Info about the current PROJ definition
urschrei marked this conversation as resolved.
Show resolved Hide resolved
///
/// [PROJ reference documentation](https://proj.org/development/reference/datatypes.html?highlight=has_inverse#c.PJ_PROJ_INFO)
#[derive(Clone, Debug)]
pub struct ProjInfo {
pub id: Option<String>,
pub description: Option<String>,
pub definition: Option<String>,
pub has_inverse: bool,
pub accuracy: f64,
}

impl fmt::Debug for Proj {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let pj_info = self.pj_info();
let pj_info = self.proj_info();
f.debug_struct("Proj")
.field("id", &pj_info.id)
.field("description", &pj_info.description)
Expand Down Expand Up @@ -1164,7 +1175,7 @@ mod test {
fn test_searchpath() {
let mut tf = ProjBuilder::new();
tf.set_search_paths(&"/foo").unwrap();
let ipath = tf.info().unwrap().searchpath;
let ipath = tf.lib_info().unwrap().searchpath;
let pathsep = if cfg!(windows) { ";" } else { ":" };
let individual: Vec<&str> = ipath.split(pathsep).collect();
assert_eq!(&individual.last().unwrap(), &&"/foo")
Expand Down