Skip to content

Commit

Permalink
Merge pull request #72 from georust/debug
Browse files Browse the repository at this point in the history
Add Debug implementation for proj::Proj
  • Loading branch information
frewsxcv authored Feb 12, 2021
2 parents c634238 + ab61638 commit 81b233a
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 33 deletions.
22 changes: 9 additions & 13 deletions src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ pub(crate) unsafe extern "C" fn network_open(
}

/// Where the ACTUAL work happens, taking advantage of Rust error-handling etc
fn _network_open(
unsafe fn _network_open(
_: *mut PJ_CONTEXT,
url: *const c_char,
offset: c_ulonglong,
Expand Down Expand Up @@ -173,14 +173,12 @@ fn _network_open(
error_handler(&mut res, eh_rb)?;
// Write the initial read length value into the pointer
let contentlength = res.content_length().ok_or(ProjError::ContentLength)? as usize;
unsafe { out_size_read.write(contentlength) };
out_size_read.write(contentlength);
let headers = res.headers().clone();
// Copy the downloaded bytes into the buffer so it can be passed around
unsafe {
&res.bytes()?
.as_ptr()
.copy_to_nonoverlapping(buffer as *mut u8, contentlength.min(size_to_read))
};
&res.bytes()?
.as_ptr()
.copy_to_nonoverlapping(buffer as *mut u8, contentlength.min(size_to_read));
// Store req into the handle so new ranges can be queried
let hd = HandleData::new(req, headers, None);
// heap-allocate the struct and cast it to a void pointer so it can be passed around to PROJ
Expand All @@ -189,10 +187,8 @@ fn _network_open(
let opaque: *mut PROJ_NETWORK_HANDLE = void as *mut PROJ_NETWORK_HANDLE;
// If everything's OK, set the error string to empty
let err_string = "";
unsafe {
out_error_string.copy_from_nonoverlapping(err_string.as_ptr().cast(), err_string.len());
out_error_string.add(err_string.len()).write(0);
}
out_error_string.copy_from_nonoverlapping(err_string.as_ptr().cast(), err_string.len());
out_error_string.add(err_string.len()).write(0);
Ok(opaque)
}

Expand Down Expand Up @@ -237,14 +233,14 @@ pub(crate) unsafe extern "C" fn network_get_header_value(
}

/// Network callback: get header value
fn _network_get_header_value(
unsafe fn _network_get_header_value(
_: *mut PJ_CONTEXT,
handle: *mut PROJ_NETWORK_HANDLE,
header_name: *const c_char,
_: *mut c_void,
) -> Result<*const c_char, ProjError> {
let lookup = _string(header_name)?.to_lowercase();
let mut hd = unsafe { &mut *(handle as *mut c_void as *mut HandleData) };
let mut hd = &mut *(handle as *mut c_void as *mut HandleData);
let hvalue = hd
.headers
.get(&lookup)
Expand Down
108 changes: 88 additions & 20 deletions src/proj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use proj_sys::{
proj_trans, proj_trans_array, PJconsts, PJ_AREA, PJ_CONTEXT, PJ_COORD, PJ_DIRECTION_PJ_FWD,
PJ_DIRECTION_PJ_INV, PJ_INFO, PJ_LP, PJ_XY,
};
use std::fmt::Debug;
use std::fmt::{self, Debug};

#[cfg(feature = "network")]
use proj_sys::proj_context_set_enable_network;
Expand Down Expand Up @@ -124,15 +124,18 @@ impl Area {
}

/// Easily get a String from the external library
pub(crate) fn _string(raw_ptr: *const c_char) -> Result<String, ProjError> {
let c_str = unsafe { CStr::from_ptr(raw_ptr) };
pub(crate) unsafe fn _string(raw_ptr: *const c_char) -> Result<String, ProjError> {
assert!(!raw_ptr.is_null());
let c_str = CStr::from_ptr(raw_ptr);
Ok(str::from_utf8(c_str.to_bytes())?.to_string())
}

/// Look up an error message using the error code
fn error_message(code: c_int) -> Result<String, ProjError> {
let rv = unsafe { proj_errno_string(code) };
_string(rv)
unsafe {
let rv = proj_errno_string(code);
_string(rv)
}
}

/// Set the bounding box of the area of use
Expand Down Expand Up @@ -196,15 +199,17 @@ pub trait Info {
/// # Safety
/// This method contains unsafe code.
fn info(&self) -> Result<Projinfo, ProjError> {
let pinfo: PJ_INFO = unsafe { 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)?,
})
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)?,
})
}
}

/// 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.
Expand Down Expand Up @@ -544,7 +549,14 @@ impl Proj {
let south = unsafe { out_south_lat_degree.assume_init() };
let east = unsafe { out_east_lon_degree.assume_init() };
let north = unsafe { out_north_lat_degree.assume_init() };
let name = unsafe { out_area_name.assume_init() };
let name = unsafe {
let name = out_area_name.assume_init();
if !name.is_null() {
Some(_string(name)?)
} else {
None
}
};

let area = if west != -1000.0 && south != -1000.0 && east != -1000.0 && north != -1000.0
{
Expand All @@ -557,12 +569,36 @@ impl Proj {
} else {
None
};
let name = if !name.is_null() {
Some(_string(name)?)
Ok((area, name))
}
}

fn pj_info(&self) -> PjInfo {
unsafe {
let pj_info = proj_pj_info(self.c_proj);
let id = if pj_info.id.is_null() {
None
} else {
Some(_string(pj_info.id).expect("PROJ built an invalid string"))
};
let description = if pj_info.description.is_null() {
None
} else {
Some(_string(pj_info.description).expect("PROJ built an invalid string"))
};
Ok((area, name))
let definition = if pj_info.definition.is_null() {
None
} else {
Some(_string(pj_info.definition).expect("PROJ built an invalid string"))
};
let has_inverse = pj_info.has_inverse == 1;
PjInfo {
id,
description,
definition,
has_inverse,
accuracy: pj_info.accuracy,
}
}
}

Expand All @@ -571,8 +607,7 @@ impl Proj {
/// # Safety
/// This method contains unsafe code.
pub fn def(&self) -> Result<String, ProjError> {
let rv = unsafe { proj_pj_info(self.c_proj) };
_string(rv.definition)
Ok(self.pj_info().definition.expect("proj_pj_info did not provide a definition"))
}

/// Project geodetic coordinates (in radians) into the projection specified by `definition`
Expand Down Expand Up @@ -826,6 +861,27 @@ impl Proj {
}
}

struct PjInfo {
id: Option<String>,
description: Option<String>,
definition: Option<String>,
has_inverse: bool,
accuracy: f64,
}

impl fmt::Debug for Proj {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let pj_info = self.pj_info();
f.debug_struct("Proj")
.field("id", &pj_info.id)
.field("description", &pj_info.description)
.field("definition", &pj_info.definition)
.field("has_inverse", &pj_info.has_inverse)
.field("accuracy", &pj_info.accuracy)
.finish()
}
}

impl Drop for Proj {
fn drop(&mut self) {
unsafe {
Expand Down Expand Up @@ -933,6 +989,18 @@ mod test {
"proj=longlat datum=WGS84 no_defs ellps=WGS84 towgs84=0,0,0"
);
}

#[test]
fn test_debug() {
let wgs84 = "+proj=longlat +datum=WGS84 +no_defs";
let proj = Proj::new(wgs84).unwrap();
let debug_string = format!("{:?}", proj);
assert_eq!(
"Proj { id: Some(\"longlat\"), description: Some(\"PROJ-based coordinate operation\"), definition: Some(\"proj=longlat datum=WGS84 no_defs ellps=WGS84 towgs84=0,0,0\"), has_inverse: true, accuracy: -1.0 }",
debug_string
);
}

#[test]
#[should_panic]
// This failure is a bug in libproj
Expand Down

0 comments on commit 81b233a

Please sign in to comment.