Skip to content

Commit 81b233a

Browse files
authored
Merge pull request #72 from georust/debug
Add Debug implementation for proj::Proj
2 parents c634238 + ab61638 commit 81b233a

File tree

2 files changed

+97
-33
lines changed

2 files changed

+97
-33
lines changed

src/network.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ pub(crate) unsafe extern "C" fn network_open(
142142
}
143143

144144
/// Where the ACTUAL work happens, taking advantage of Rust error-handling etc
145-
fn _network_open(
145+
unsafe fn _network_open(
146146
_: *mut PJ_CONTEXT,
147147
url: *const c_char,
148148
offset: c_ulonglong,
@@ -173,14 +173,12 @@ fn _network_open(
173173
error_handler(&mut res, eh_rb)?;
174174
// Write the initial read length value into the pointer
175175
let contentlength = res.content_length().ok_or(ProjError::ContentLength)? as usize;
176-
unsafe { out_size_read.write(contentlength) };
176+
out_size_read.write(contentlength);
177177
let headers = res.headers().clone();
178178
// Copy the downloaded bytes into the buffer so it can be passed around
179-
unsafe {
180-
&res.bytes()?
181-
.as_ptr()
182-
.copy_to_nonoverlapping(buffer as *mut u8, contentlength.min(size_to_read))
183-
};
179+
&res.bytes()?
180+
.as_ptr()
181+
.copy_to_nonoverlapping(buffer as *mut u8, contentlength.min(size_to_read));
184182
// Store req into the handle so new ranges can be queried
185183
let hd = HandleData::new(req, headers, None);
186184
// heap-allocate the struct and cast it to a void pointer so it can be passed around to PROJ
@@ -189,10 +187,8 @@ fn _network_open(
189187
let opaque: *mut PROJ_NETWORK_HANDLE = void as *mut PROJ_NETWORK_HANDLE;
190188
// If everything's OK, set the error string to empty
191189
let err_string = "";
192-
unsafe {
193-
out_error_string.copy_from_nonoverlapping(err_string.as_ptr().cast(), err_string.len());
194-
out_error_string.add(err_string.len()).write(0);
195-
}
190+
out_error_string.copy_from_nonoverlapping(err_string.as_ptr().cast(), err_string.len());
191+
out_error_string.add(err_string.len()).write(0);
196192
Ok(opaque)
197193
}
198194

@@ -237,14 +233,14 @@ pub(crate) unsafe extern "C" fn network_get_header_value(
237233
}
238234

239235
/// Network callback: get header value
240-
fn _network_get_header_value(
236+
unsafe fn _network_get_header_value(
241237
_: *mut PJ_CONTEXT,
242238
handle: *mut PROJ_NETWORK_HANDLE,
243239
header_name: *const c_char,
244240
_: *mut c_void,
245241
) -> Result<*const c_char, ProjError> {
246242
let lookup = _string(header_name)?.to_lowercase();
247-
let mut hd = unsafe { &mut *(handle as *mut c_void as *mut HandleData) };
243+
let mut hd = &mut *(handle as *mut c_void as *mut HandleData);
248244
let hvalue = hd
249245
.headers
250246
.get(&lookup)

src/proj.rs

Lines changed: 88 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use proj_sys::{
1010
proj_trans, proj_trans_array, PJconsts, PJ_AREA, PJ_CONTEXT, PJ_COORD, PJ_DIRECTION_PJ_FWD,
1111
PJ_DIRECTION_PJ_INV, PJ_INFO, PJ_LP, PJ_XY,
1212
};
13-
use std::fmt::Debug;
13+
use std::fmt::{self, Debug};
1414

1515
#[cfg(feature = "network")]
1616
use proj_sys::proj_context_set_enable_network;
@@ -124,15 +124,18 @@ impl Area {
124124
}
125125

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

132133
/// Look up an error message using the error code
133134
fn error_message(code: c_int) -> Result<String, ProjError> {
134-
let rv = unsafe { proj_errno_string(code) };
135-
_string(rv)
135+
unsafe {
136+
let rv = proj_errno_string(code);
137+
_string(rv)
138+
}
136139
}
137140

138141
/// Set the bounding box of the area of use
@@ -196,15 +199,17 @@ pub trait Info {
196199
/// # Safety
197200
/// This method contains unsafe code.
198201
fn info(&self) -> Result<Projinfo, ProjError> {
199-
let pinfo: PJ_INFO = unsafe { proj_info() };
200-
Ok(Projinfo {
201-
major: pinfo.major,
202-
minor: pinfo.minor,
203-
patch: pinfo.patch,
204-
release: _string(pinfo.release)?,
205-
version: _string(pinfo.version)?,
206-
searchpath: _string(pinfo.searchpath)?,
207-
})
202+
unsafe {
203+
let pinfo: PJ_INFO = proj_info();
204+
Ok(Projinfo {
205+
major: pinfo.major,
206+
minor: pinfo.minor,
207+
patch: pinfo.patch,
208+
release: _string(pinfo.release)?,
209+
version: _string(pinfo.version)?,
210+
searchpath: _string(pinfo.searchpath)?,
211+
})
212+
}
208213
}
209214

210215
/// 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.
@@ -544,7 +549,14 @@ impl Proj {
544549
let south = unsafe { out_south_lat_degree.assume_init() };
545550
let east = unsafe { out_east_lon_degree.assume_init() };
546551
let north = unsafe { out_north_lat_degree.assume_init() };
547-
let name = unsafe { out_area_name.assume_init() };
552+
let name = unsafe {
553+
let name = out_area_name.assume_init();
554+
if !name.is_null() {
555+
Some(_string(name)?)
556+
} else {
557+
None
558+
}
559+
};
548560

549561
let area = if west != -1000.0 && south != -1000.0 && east != -1000.0 && north != -1000.0
550562
{
@@ -557,12 +569,36 @@ impl Proj {
557569
} else {
558570
None
559571
};
560-
let name = if !name.is_null() {
561-
Some(_string(name)?)
572+
Ok((area, name))
573+
}
574+
}
575+
576+
fn pj_info(&self) -> PjInfo {
577+
unsafe {
578+
let pj_info = proj_pj_info(self.c_proj);
579+
let id = if pj_info.id.is_null() {
580+
None
562581
} else {
582+
Some(_string(pj_info.id).expect("PROJ built an invalid string"))
583+
};
584+
let description = if pj_info.description.is_null() {
563585
None
586+
} else {
587+
Some(_string(pj_info.description).expect("PROJ built an invalid string"))
564588
};
565-
Ok((area, name))
589+
let definition = if pj_info.definition.is_null() {
590+
None
591+
} else {
592+
Some(_string(pj_info.definition).expect("PROJ built an invalid string"))
593+
};
594+
let has_inverse = pj_info.has_inverse == 1;
595+
PjInfo {
596+
id,
597+
description,
598+
definition,
599+
has_inverse,
600+
accuracy: pj_info.accuracy,
601+
}
566602
}
567603
}
568604

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

578613
/// Project geodetic coordinates (in radians) into the projection specified by `definition`
@@ -826,6 +861,27 @@ impl Proj {
826861
}
827862
}
828863

864+
struct PjInfo {
865+
id: Option<String>,
866+
description: Option<String>,
867+
definition: Option<String>,
868+
has_inverse: bool,
869+
accuracy: f64,
870+
}
871+
872+
impl fmt::Debug for Proj {
873+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
874+
let pj_info = self.pj_info();
875+
f.debug_struct("Proj")
876+
.field("id", &pj_info.id)
877+
.field("description", &pj_info.description)
878+
.field("definition", &pj_info.definition)
879+
.field("has_inverse", &pj_info.has_inverse)
880+
.field("accuracy", &pj_info.accuracy)
881+
.finish()
882+
}
883+
}
884+
829885
impl Drop for Proj {
830886
fn drop(&mut self) {
831887
unsafe {
@@ -933,6 +989,18 @@ mod test {
933989
"proj=longlat datum=WGS84 no_defs ellps=WGS84 towgs84=0,0,0"
934990
);
935991
}
992+
993+
#[test]
994+
fn test_debug() {
995+
let wgs84 = "+proj=longlat +datum=WGS84 +no_defs";
996+
let proj = Proj::new(wgs84).unwrap();
997+
let debug_string = format!("{:?}", proj);
998+
assert_eq!(
999+
"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 }",
1000+
debug_string
1001+
);
1002+
}
1003+
9361004
#[test]
9371005
#[should_panic]
9381006
// This failure is a bug in libproj

0 commit comments

Comments
 (0)