diff --git a/cspice-sys/Cargo.toml b/cspice-sys/Cargo.toml index d3ba289..fe1eb89 100644 --- a/cspice-sys/Cargo.toml +++ b/cspice-sys/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cspice-sys" -version = "1.0.3" +version = "1.0.4" edition = "2021" build = "build.rs" description = "Unsafe bindings to the NAIF CSPICE toolkit" diff --git a/cspice-sys/build.rs b/cspice-sys/build.rs index 0f00b4c..2b05e46 100644 --- a/cspice-sys/build.rs +++ b/cspice-sys/build.rs @@ -122,17 +122,17 @@ fn download_cspice(out_dir: &Path) { match (env::consts::OS, extension) { ("linux" | "macos", "tar.Z") => { Command::new("gzip") - .current_dir(&out_dir) + .current_dir(out_dir) .args(["-d", "cspice.tar.Z"]) .status() .expect("Failed to extract with gzip"); Command::new("tar") - .current_dir(&out_dir) + .current_dir(out_dir) .args(["xf", "cspice.tar"]) .status() .expect("Failed to extract with tar"); - std::fs::rename( + fs::rename( out_dir.join("cspice/lib/cspice.a"), out_dir.join("cspice/lib/libcspice.a"), ) @@ -140,7 +140,7 @@ fn download_cspice(out_dir: &Path) { } ("windows", "zip") => { Command::new("tar") - .current_dir(&out_dir) + .current_dir(out_dir) .args(["xf", "cspice.zip"]) .status() .expect("Failed to extract with tar"); diff --git a/cspice/Cargo.toml b/cspice/Cargo.toml index f123975..44dca2b 100644 --- a/cspice/Cargo.toml +++ b/cspice/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cspice" -version = "0.0.1" +version = "0.1.0" edition = "2021" description = "Safe wrapper around the NAIF CSPICE toolkit" license = "LGPL-3.0" @@ -10,9 +10,9 @@ repository = "https://github.com/jacob-pro/cspice-rs" [dependencies] chrono = { version = "0.4.19", optional = true } -cspice-sys = { path = "../cspice-sys", version = "1.0.3" } +cspice-sys = { path = "../cspice-sys", version = "1.0.4" } derive_more = "0.99.17" -once_cell = "1.12.0" +parking_lot = "0.12.1" serde = { version = "1.0.137", features = ["derive"] } serde_plain = "1.0.0" thiserror = "1.0.31" diff --git a/cspice/src/cell.rs b/cspice/src/cell.rs index 8c301df..076e128 100644 --- a/cspice/src/cell.rs +++ b/cspice/src/cell.rs @@ -2,7 +2,7 @@ use crate::common::{ComparisonOperator, Side}; use crate::error::get_last_error; use crate::string::StringParam; -use crate::{spice_unsafe, Error}; +use crate::{with_spice_lock_or_panic, Error}; use cspice_sys::{ _SpiceDataType_SPICE_CHR, _SpiceDataType_SPICE_DP, _SpiceDataType_SPICE_INT, appndc_c, appndd_c, appndi_c, card_c, copy_c, scard_c, wncard_c, wncomd_c, wncond_c, wndifd_c, wnelmd_c, @@ -36,38 +36,42 @@ impl Cell { /// /// See [scard_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/scard_c.html). pub fn set_cardinality(&mut self, cardinality: usize) -> Result<(), Error> { - spice_unsafe!({ - scard_c(cardinality as SpiceInt, self.as_mut_cell()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { scard_c(cardinality as SpiceInt, self.as_mut_cell()) }; + get_last_error() + }) } /// Return the size (maximum cardinality) of a SPICE cell. /// /// See [size_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/size_c.html) pub fn get_size(&mut self) -> Result { - let out = spice_unsafe!({ card_c(self.as_mut_cell()) }); - get_last_error()?; - Ok(out as usize) + with_spice_lock_or_panic(|| { + let out = unsafe { card_c(self.as_mut_cell()) }; + get_last_error()?; + Ok(out as usize) + }) } /// Return the cardinality (current number of elements) in a cell. /// /// See [card_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/card_c.html). pub fn get_cardinality(&mut self) -> Result { - let out = spice_unsafe!({ card_c(self.as_mut_cell()) }); - get_last_error()?; - Ok(out as usize) + with_spice_lock_or_panic(|| { + let out = unsafe { card_c(self.as_mut_cell()) }; + get_last_error()?; + Ok(out as usize) + }) } /// Copy the contents of a SpiceCell of any data type to another cell of the same type. /// /// See [copy_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/copy_c.html). pub fn copy(&mut self, dest: &mut Cell) -> Result<(), Error> { - spice_unsafe!({ - copy_c(self.as_mut_cell(), dest.as_mut_cell()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { copy_c(self.as_mut_cell(), dest.as_mut_cell()) }; + get_last_error() + }) } } @@ -95,10 +99,10 @@ impl Cell { /// /// See [appndd_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/appndd_c.html) pub fn append(&mut self, item: SpiceDouble) -> Result<(), Error> { - spice_unsafe!({ - appndd_c(item, self.as_mut_cell()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { appndd_c(item, self.as_mut_cell()) }; + get_last_error() + }) } } @@ -126,10 +130,10 @@ impl Cell { /// /// See [appndi_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/appndi_c.html) pub fn append(&mut self, item: SpiceInt) -> Result<(), Error> { - spice_unsafe!({ - appndi_c(item, self.as_mut_cell()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { appndi_c(item, self.as_mut_cell()) }; + get_last_error() + }) } } @@ -138,7 +142,7 @@ impl Cell { /// /// See [Character Cells](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/cells.html#Character%20Cells) pub fn new_char(size: usize, length: usize) -> Self { - let data_len = (SPICE_CELL_CTRLSZ as usize + size) as usize * length; + let data_len = (SPICE_CELL_CTRLSZ as usize + size) * length; let start_index = SPICE_CELL_CTRLSZ as usize * length; let mut data = vec![0; data_len]; let cell = cspice_sys::SpiceCell { @@ -159,10 +163,10 @@ impl Cell { /// /// See [appndc_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/appndc_c.html) pub fn append<'s, S: Into>>(&mut self, item: S) -> Result<(), Error> { - spice_unsafe!({ - appndc_c(item.into().as_mut_ptr(), self.as_mut_cell()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { appndc_c(item.into().as_mut_ptr(), self.as_mut_cell()) }; + get_last_error() + }) } } @@ -186,9 +190,11 @@ impl Cell { /// /// See [wncard_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/wncard_c.html). pub fn window_cardinality(&mut self) -> Result { - let out = spice_unsafe!({ wncard_c(self.as_mut_cell()) }); - get_last_error()?; - Ok(out) + with_spice_lock_or_panic(|| { + let out = unsafe { wncard_c(self.as_mut_cell()) }; + get_last_error()?; + Ok(out) + }) } /// Determine the complement of a double precision window with respect to a specified interval. @@ -200,20 +206,20 @@ impl Cell { right: SpiceDouble, output: &mut Window, ) -> Result<(), Error> { - spice_unsafe!({ - wncomd_c(left, right, self.as_mut_cell(), output.as_mut_cell()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { wncomd_c(left, right, self.as_mut_cell(), output.as_mut_cell()) }; + get_last_error() + }) } /// Contract each of the intervals of a double precision window. /// /// See [wncond_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/wncond_c.html). pub fn window_contract(&mut self, left: SpiceDouble, right: SpiceDouble) -> Result<(), Error> { - spice_unsafe!({ - wncond_c(left, right, self.as_mut_cell()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { wncond_c(left, right, self.as_mut_cell()) }; + get_last_error() + }) } /// Place the difference of two double precision windows into a third window. @@ -224,75 +230,83 @@ impl Cell { other: &mut Window, output: &mut Window, ) -> Result<(), Error> { - spice_unsafe!({ - wndifd_c( - self.as_mut_cell(), - other.as_mut_cell(), - output.as_mut_cell(), - ); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { + wndifd_c( + self.as_mut_cell(), + other.as_mut_cell(), + output.as_mut_cell(), + ); + }; + get_last_error() + }) } /// Determine whether a point is an element of a double precision window /// /// See [wnelmd_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/wnelmd_c.html). pub fn window_contains_element(&mut self, point: SpiceDouble) -> Result { - let out = spice_unsafe!({ wnelmd_c(point, self.as_mut_cell()) }); - get_last_error()?; - Ok(out == SPICETRUE as SpiceBoolean) + with_spice_lock_or_panic(|| { + let out = unsafe { wnelmd_c(point, self.as_mut_cell()) }; + get_last_error()?; + Ok(out == SPICETRUE as SpiceBoolean) + }) } /// Expand each of the intervals of a double precision window /// /// See [wnexpd_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/wnexpd_c.html). pub fn window_expand(&mut self, left: SpiceDouble, right: SpiceDouble) -> Result<(), Error> { - spice_unsafe!({ - wnexpd_c(left, right, self.as_mut_cell()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { wnexpd_c(left, right, self.as_mut_cell()) }; + get_last_error() + }) } /// Extract the left or right endpoints from a double precision window. /// /// See [wnextd_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/wnextd_c.html). pub fn window_extract(&mut self, side: Side) -> Result<(), Error> { - spice_unsafe!({ - wnextd_c(side.as_spice_char(), self.as_mut_cell()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { wnextd_c(side.as_spice_char(), self.as_mut_cell()) }; + get_last_error() + }) } /// Fetch a particular interval from a double precision window. /// /// See [wnfetd_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/wnfetd_c.html). pub fn window_interval(&mut self, n: usize) -> Result<(SpiceDouble, SpiceDouble), Error> { - let (mut left, mut right) = (0.0, 0.0); - spice_unsafe!({ - wnfetd_c(self.as_mut_cell(), n as SpiceInt, &mut left, &mut right); - }); - get_last_error()?; - Ok((left, right)) + with_spice_lock_or_panic(|| { + let (mut left, mut right) = (0.0, 0.0); + unsafe { + wnfetd_c(self.as_mut_cell(), n as SpiceInt, &mut left, &mut right); + }; + get_last_error()?; + Ok((left, right)) + }) } /// Fill small gaps between adjacent intervals of a double precision window. /// /// See [wnfild_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/wnfild_c.html). pub fn window_fill(&mut self, small_gap: SpiceDouble) -> Result<(), Error> { - spice_unsafe!({ - wnfild_c(small_gap, self.as_mut_cell()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { wnfild_c(small_gap, self.as_mut_cell()) }; + get_last_error() + }) } /// Filter (remove) small intervals from a double precision window. /// /// See [wnfltd_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/wnfltd_c.html). pub fn window_filter(&mut self, small_interval: SpiceDouble) -> Result<(), Error> { - spice_unsafe!({ - wnfltd_c(small_interval, self.as_mut_cell()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { + wnfltd_c(small_interval, self.as_mut_cell()); + }; + get_last_error() + }) } /// Determine whether an interval is included in a double precision window. @@ -303,9 +317,11 @@ impl Cell { left: SpiceDouble, right: SpiceDouble, ) -> Result { - let out = spice_unsafe!({ wnincd_c(left, right, self.as_mut_cell()) }); - get_last_error()?; - Ok(out == SPICETRUE as SpiceBoolean) + with_spice_lock_or_panic(|| { + let out = unsafe { wnincd_c(left, right, self.as_mut_cell()) }; + get_last_error()?; + Ok(out == SPICETRUE as SpiceBoolean) + }) } /// Insert an interval into a double precision window. @@ -316,8 +332,10 @@ impl Cell { left: SpiceDouble, right: SpiceDouble, ) -> Result<(), Error> { - spice_unsafe!({ wninsd_c(left, right, self.as_mut_cell()) }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { wninsd_c(left, right, self.as_mut_cell()) }; + get_last_error() + }) } /// Place the intersection of two double precision windows into a third window. @@ -328,14 +346,16 @@ impl Cell { other: &mut Window, output: &mut Window, ) -> Result<(), Error> { - spice_unsafe!({ - wnintd_c( - self.as_mut_cell(), - other.as_mut_cell(), - output.as_mut_cell(), - ) - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { + wnintd_c( + self.as_mut_cell(), + other.as_mut_cell(), + output.as_mut_cell(), + ) + }; + get_last_error() + }) } /// Compare two double precision windows. @@ -346,40 +366,44 @@ impl Cell { comparison_op: ComparisonOperator, other: &mut Window, ) -> Result { - let out = spice_unsafe!({ - wnreld_c( - self.as_mut_cell(), - comparison_op.as_spice_char(), - other.as_mut_cell(), - ) - }); - get_last_error()?; - Ok(out == SPICETRUE as SpiceBoolean) + with_spice_lock_or_panic(|| { + let out = unsafe { + wnreld_c( + self.as_mut_cell(), + comparison_op.as_spice_char(), + other.as_mut_cell(), + ) + }; + get_last_error()?; + Ok(out == SPICETRUE as SpiceBoolean) + }) } /// Summarize the contents of a double precision window. /// /// See [wnsumd_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/wnsumd_c.html). pub fn window_summarize(&mut self) -> Result { - let (mut meas, mut avg, mut stddev) = (0.0, 0.0, 0.0); - let (mut idxsml, mut idxlon) = (0, 0); - spice_unsafe!({ - wnsumd_c( - self.as_mut_cell(), - &mut meas, - &mut avg, - &mut stddev, - &mut idxsml, - &mut idxlon, - ) - }); - get_last_error()?; - Ok(WindowSummary { - total_measure_of_intervals: meas, - average_measure: avg, - standard_deviation: stddev, - shortest_interval_index: idxsml as usize, - longest_interval_index: idxlon as usize, + with_spice_lock_or_panic(|| { + let (mut meas, mut avg, mut stddev) = (0.0, 0.0, 0.0); + let (mut idxsml, mut idxlon) = (0, 0); + unsafe { + wnsumd_c( + self.as_mut_cell(), + &mut meas, + &mut avg, + &mut stddev, + &mut idxsml, + &mut idxlon, + ) + }; + get_last_error()?; + Ok(WindowSummary { + total_measure_of_intervals: meas, + average_measure: avg, + standard_deviation: stddev, + shortest_interval_index: idxsml as usize, + longest_interval_index: idxlon as usize, + }) }) } @@ -387,21 +411,25 @@ impl Cell { /// /// See [wnunid_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/wnunid_c.html). pub fn window_union(&mut self, other: &mut Window, output: &mut Window) -> Result<(), Error> { - spice_unsafe!({ - wnunid_c( - self.as_mut_cell(), - other.as_mut_cell(), - output.as_mut_cell(), - ); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { + wnunid_c( + self.as_mut_cell(), + other.as_mut_cell(), + output.as_mut_cell(), + ) + }; + get_last_error() + }) } /// Form a valid double precision window from the contents of a window array. /// /// See [wnvald_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/wnvald_c.html). pub fn window_validate(&mut self, size: usize, n: usize) -> Result<(), Error> { - spice_unsafe!({ wnvald_c(size as SpiceInt, n as SpiceInt, self.as_mut_cell()) }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { wnvald_c(size as SpiceInt, n as SpiceInt, self.as_mut_cell()) }; + get_last_error() + }) } } diff --git a/cspice/src/coordinates.rs b/cspice/src/coordinates.rs index 56867ef..10e1f92 100644 --- a/cspice/src/coordinates.rs +++ b/cspice/src/coordinates.rs @@ -1,5 +1,5 @@ //! Functions for converting between different types of coordinates. -use crate::spice_unsafe; +use crate::with_spice_lock_or_panic; use cspice_sys::{azlrec_c, recazl_c, reclat_c, recrad_c, SpiceBoolean, SpiceDouble}; use derive_more::Into; @@ -39,36 +39,40 @@ pub struct AzEl { impl AzEl { /// See [recazl_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/recazl_c.html) pub fn from_rect(mut rect: Rectangular, azccw: bool, elplsz: bool) -> Self { - let mut az_el = AzEl::default(); - spice_unsafe!({ - recazl_c( - &mut rect.x as *mut SpiceDouble, - azccw as SpiceBoolean, - elplsz as SpiceBoolean, - &mut az_el.range, - &mut az_el.az, - &mut az_el.el, - ) - }); - az_el + with_spice_lock_or_panic(|| { + let mut az_el = AzEl::default(); + unsafe { + recazl_c( + &mut rect.x as *mut SpiceDouble, + azccw as SpiceBoolean, + elplsz as SpiceBoolean, + &mut az_el.range, + &mut az_el.az, + &mut az_el.el, + ) + }; + az_el + }) } } impl Rectangular { /// See [azlrec_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/azlrec_c.html) pub fn from_azel(azel: AzEl, azccw: bool, elplsz: bool) -> Self { - let mut rect = [0.0f64; 3]; - spice_unsafe!({ - azlrec_c( - azel.range, - azel.az, - azel.el, - azccw as SpiceBoolean, - elplsz as SpiceBoolean, - rect.as_mut_ptr(), - ) - }); - rect.into() + with_spice_lock_or_panic(|| { + let mut rect = [0.0f64; 3]; + unsafe { + azlrec_c( + azel.range, + azel.az, + azel.el, + azccw as SpiceBoolean, + elplsz as SpiceBoolean, + rect.as_mut_ptr(), + ) + }; + rect.into() + }) } } @@ -83,16 +87,18 @@ pub struct RaDec { impl From for RaDec { /// See [recrad_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/recrad_c.html). fn from(mut rect: Rectangular) -> Self { - let mut ra_dec = RaDec::default(); - spice_unsafe!({ - recrad_c( - &mut rect.x as *mut SpiceDouble, - &mut ra_dec.range, - &mut ra_dec.ra, - &mut ra_dec.dec, - ) - }); - ra_dec + with_spice_lock_or_panic(|| { + let mut ra_dec = RaDec::default(); + unsafe { + recrad_c( + &mut rect.x as *mut SpiceDouble, + &mut ra_dec.range, + &mut ra_dec.ra, + &mut ra_dec.dec, + ) + }; + ra_dec + }) } } @@ -107,16 +113,18 @@ pub struct Latitudinal { impl From for Latitudinal { /// See [reclat_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/reclat_c.html). fn from(mut rect: Rectangular) -> Self { - let mut lat = Latitudinal::default(); - spice_unsafe!({ - reclat_c( - &mut rect.x as *mut SpiceDouble, - &mut lat.radius, - &mut lat.longitude, - &mut lat.latitude, - ) - }); - lat + with_spice_lock_or_panic(|| { + let mut lat = Latitudinal::default(); + unsafe { + reclat_c( + &mut rect.x as *mut SpiceDouble, + &mut lat.radius, + &mut lat.longitude, + &mut lat.latitude, + ) + }; + lat + }) } } diff --git a/cspice/src/data.rs b/cspice/src/data.rs index 9ec3de7..436487d 100644 --- a/cspice/src/data.rs +++ b/cspice/src/data.rs @@ -1,27 +1,31 @@ //! Functions for loading and unloading SPICE Kernels. use crate::error::get_last_error; use crate::string::StringParam; -use crate::{spice_unsafe, Error}; +use crate::{with_spice_lock_or_panic, Error}; use cspice_sys::{furnsh_c, unload_c}; /// Load one or more SPICE kernels into a program. /// /// See [furnsh_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/furnsh_c.html). pub fn furnish<'f, F: Into>>(file: F) -> Result<(), Error> { - spice_unsafe!({ - furnsh_c(file.into().as_mut_ptr()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { + furnsh_c(file.into().as_mut_ptr()); + }; + get_last_error() + }) } /// Unload a SPICE kernel. /// /// See [unload_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/unload_c.html). pub fn unload<'f, F: Into>>(file: F) -> Result<(), Error> { - spice_unsafe!({ - unload_c(file.into().as_mut_ptr()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { + unload_c(file.into().as_mut_ptr()); + }; + get_last_error() + }) } #[cfg(test)] diff --git a/cspice/src/error.rs b/cspice/src/error.rs index 8536a33..9386d11 100644 --- a/cspice/src/error.rs +++ b/cspice/src/error.rs @@ -1,7 +1,7 @@ //! Functions relating to error handling. use crate::common::{GET, SET}; -use crate::spice_unsafe; use crate::string::{SpiceStr, SpiceString}; +use crate::with_spice_lock_or_panic; use cspice_sys::{ erract_c, errdev_c, failed_c, getmsg_c, qcktrc_c, reset_c, SpiceInt, SPICE_ERROR_LMSGLN, SPICE_ERROR_SMSGLN, SPICE_ERROR_TRCLEN, SPICE_ERROR_XMSGLN, @@ -45,45 +45,47 @@ pub enum ErrorDevice { /// For context see [CSPICE Error Handling](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/error.html#Testing%20the%20Error%20Status). #[inline] pub fn get_last_error() -> Result<(), Error> { - spice_unsafe!({ - if failed_c() == 0 { - return Ok(()); + with_spice_lock_or_panic(|| { + unsafe { + if failed_c() == 0 { + return Ok(()); + } + + // Gather error info + let option = SpiceString::from("SHORT"); + let mut short_message = [0; SPICE_ERROR_SMSGLN as usize]; + getmsg_c( + option.as_mut_ptr(), + short_message.len() as SpiceInt, + short_message.as_mut_ptr(), + ); + let option = SpiceString::from("EXPLAIN"); + let mut explanation = [0; SPICE_ERROR_XMSGLN as usize]; + getmsg_c( + option.as_mut_ptr(), + explanation.len() as SpiceInt, + explanation.as_mut_ptr(), + ); + let option = SpiceString::from("LONG"); + let mut long_message = [0; SPICE_ERROR_LMSGLN as usize]; + getmsg_c( + option.as_mut_ptr(), + long_message.len() as SpiceInt, + long_message.as_mut_ptr(), + ); + let mut traceback = [0; SPICE_ERROR_TRCLEN as usize]; + qcktrc_c(traceback.len() as SpiceInt, traceback.as_mut_ptr()); + + // Reset last error + reset_c(); + + Err(Error { + short_message: SpiceStr::from_buffer(&short_message).to_string(), + explanation: SpiceStr::from_buffer(&explanation).to_string(), + long_message: SpiceStr::from_buffer(&long_message).to_string(), + traceback: SpiceStr::from_buffer(&traceback).to_string(), + }) } - - // Gather error info - let option = SpiceString::from("SHORT"); - let mut short_message = [0; SPICE_ERROR_SMSGLN as usize]; - getmsg_c( - option.as_mut_ptr(), - short_message.len() as SpiceInt, - short_message.as_mut_ptr(), - ); - let option = SpiceString::from("EXPLAIN"); - let mut explanation = [0; SPICE_ERROR_XMSGLN as usize]; - getmsg_c( - option.as_mut_ptr(), - explanation.len() as SpiceInt, - explanation.as_mut_ptr(), - ); - let option = SpiceString::from("LONG"); - let mut long_message = [0; SPICE_ERROR_LMSGLN as usize]; - getmsg_c( - option.as_mut_ptr(), - long_message.len() as SpiceInt, - long_message.as_mut_ptr(), - ); - let mut traceback = [0; SPICE_ERROR_TRCLEN as usize]; - qcktrc_c(traceback.len() as SpiceInt, traceback.as_mut_ptr()); - - // Reset last error - reset_c(); - - Err(Error { - short_message: SpiceStr::from_buffer(&short_message).to_string(), - explanation: SpiceStr::from_buffer(&explanation).to_string(), - long_message: SpiceStr::from_buffer(&long_message).to_string(), - traceback: SpiceStr::from_buffer(&traceback).to_string(), - }) }) } @@ -92,10 +94,10 @@ pub fn get_last_error() -> Result<(), Error> { /// See [erract_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/erract_c.html). pub fn set_error_action(action: ErrorAction) -> Result<(), Error> { let action = SpiceString::from(serde_plain::to_string(&action).unwrap()); - spice_unsafe!({ - erract_c(SET.as_mut_ptr(), 0, action.as_mut_ptr()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { erract_c(SET.as_mut_ptr(), 0, action.as_mut_ptr()) }; + get_last_error() + }) } /// Get the action when an error occurs in a SPICE function. @@ -103,16 +105,18 @@ pub fn set_error_action(action: ErrorAction) -> Result<(), Error> { /// See [erract_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/erract_c.html). pub fn get_error_action() -> Result { let mut buffer = [0; 20]; - spice_unsafe!({ - erract_c( - GET.as_mut_ptr(), - buffer.len() as SpiceInt, - buffer.as_mut_ptr(), - ); - }); - get_last_error()?; + with_spice_lock_or_panic(|| { + unsafe { + erract_c( + GET.as_mut_ptr(), + buffer.len() as SpiceInt, + buffer.as_mut_ptr(), + ) + }; + get_last_error() + })?; let action = SpiceStr::from_buffer(&buffer); - Ok(serde_plain::from_str(&*action.as_str()).unwrap()) + Ok(serde_plain::from_str(&action.as_str()).unwrap()) } /// Set Error Output Device. @@ -124,10 +128,10 @@ pub fn set_error_output_device(device: ErrorDevice) -> Result<(), Error> { ErrorDevice::Null => SpiceString::from("NULL"), ErrorDevice::Filename(filename) => SpiceString::from(filename), }; - spice_unsafe!({ - errdev_c(SET.as_mut_ptr(), 0, device.as_mut_ptr()); - }); - get_last_error() + with_spice_lock_or_panic(|| { + unsafe { errdev_c(SET.as_mut_ptr(), 0, device.as_mut_ptr()) }; + get_last_error() + }) } /// Get Error Output Device. @@ -135,14 +139,16 @@ pub fn set_error_output_device(device: ErrorDevice) -> Result<(), Error> { /// See [errdev_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/errdev_c.html). pub fn get_error_output_device() -> Result { let mut buffer = [0; FILEN as usize]; - spice_unsafe!({ - errdev_c( - GET.as_mut_ptr(), - buffer.len() as SpiceInt, - buffer.as_mut_ptr(), - ); - }); - get_last_error()?; + with_spice_lock_or_panic(|| { + unsafe { + errdev_c( + GET.as_mut_ptr(), + buffer.len() as SpiceInt, + buffer.as_mut_ptr(), + ); + }; + get_last_error() + })?; let action = SpiceStr::from_buffer(&buffer); Ok(match action.as_str() { s if s == "SCREEN" => ErrorDevice::Screen, diff --git a/cspice/src/gf.rs b/cspice/src/gf.rs index 4caa31e..3e7e543 100644 --- a/cspice/src/gf.rs +++ b/cspice/src/gf.rs @@ -5,7 +5,7 @@ use crate::common::AberrationCorrection; use crate::error::get_last_error; use crate::string::StaticSpiceStr; use crate::string::{static_spice_str, StringParam}; -use crate::{spice_unsafe, Error}; +use crate::{with_spice_lock_or_panic, Error}; use cspice_sys::{gfsep_c, SpiceChar, SpiceDouble, SpiceInt}; #[derive(Copy, Clone, Debug)] @@ -79,25 +79,26 @@ where F2: Into>, O: Into>, { - spice_unsafe!({ - gfsep_c( - body1.into().as_mut_ptr(), - shape1.as_spice_char(), - frame1.into().as_mut_ptr(), - body2.into().as_mut_ptr(), - shape2.as_spice_char(), - frame2.into().as_mut_ptr(), - aberration_correction.as_spice_char(), - observing_body.into().as_mut_ptr(), - relational_operator.as_spice_char(), - refval, - adjust, - step_size, - intervals as SpiceInt, - confine.as_mut_cell(), - output.as_mut_cell(), - ); - }); - get_last_error()?; - Ok(()) + with_spice_lock_or_panic(|| { + unsafe { + gfsep_c( + body1.into().as_mut_ptr(), + shape1.as_spice_char(), + frame1.into().as_mut_ptr(), + body2.into().as_mut_ptr(), + shape2.as_spice_char(), + frame2.into().as_mut_ptr(), + aberration_correction.as_spice_char(), + observing_body.into().as_mut_ptr(), + relational_operator.as_spice_char(), + refval, + adjust, + step_size, + intervals as SpiceInt, + confine.as_mut_cell(), + output.as_mut_cell(), + ); + }; + get_last_error() + }) } diff --git a/cspice/src/lib.rs b/cspice/src/lib.rs index da3fa2c..66a120e 100644 --- a/cspice/src/lib.rs +++ b/cspice/src/lib.rs @@ -9,62 +9,73 @@ pub mod string; pub mod time; pub mod vector; -pub use crate::error::Error; - use crate::error::set_error_defaults; +pub use crate::error::Error; use crate::string::SpiceString; -use once_cell::sync::OnceCell; -use std::cell::Cell; +use parking_lot::{ReentrantMutex, ReentrantMutexGuard}; +use std::cell::RefCell; use std::fmt::Debug; -use std::thread; -use std::thread::Thread; +use std::ops::Deref; use thiserror::Error; -/// Wraps an unsafe SPICE function call. -/// -/// First checks that it is safe for the current thread to access SPICE, otherwise panics. -macro_rules! spice_unsafe { - ($l:block) => {{ - if let Err(e) = crate::try_acquire_thread() { +// Boolean indicates if library has been initialised +static SPICE_LOCK: ReentrantMutex> = ReentrantMutex::new(RefCell::new(false)); + +pub(crate) fn with_spice_lock_or_panic(f: F) -> R +where + F: FnOnce() -> R, +{ + match try_with_spice_lock(f) { + Ok(k) => k, + Err(e) => { panic!("{e}") } - unsafe { $l } - }}; + } +} + +/// The SPICE library [is not thread safe](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/problems.html#Problem:%20SPICE%20code%20is%20not%20thread%20safe.). +/// This function can be used to synchronise calls to SPICE functions. +/// All safe functions in this library use this lock internally. +pub fn try_with_spice_lock(f: F) -> Result +where + F: FnOnce() -> R, +{ + let guard = SPICE_LOCK.try_lock().ok_or(SpiceLockError)?; + initialise_library(&guard); + Ok(f()) +} + +/// The SPICE library [is not thread safe](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/problems.html#Problem:%20SPICE%20code%20is%20not%20thread%20safe.). +/// This function can be used to synchronise calls to SPICE functions. +/// All safe functions in this library use this lock internally. +/// The lock is reentrant. +pub fn with_spice_lock(f: F) -> R +where + F: FnOnce() -> R, +{ + let guard = SPICE_LOCK.lock(); + initialise_library(&guard); + f() } -pub(crate) use spice_unsafe; -/// The SPICE library [is not thread safe](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/req/problems.html#Problem:%20SPICE%20code%20is%20not%20thread%20safe). -/// This function checks if it is safe for the current thread to call SPICE functions. SPICE -/// will be locked to the first thread that calls this function. -pub fn try_acquire_thread() -> Result<(), SpiceThreadError> { - static SPICE_THREAD_ID: OnceCell = OnceCell::new(); - thread_local! { - static CACHE: Cell = Cell::new(false); +fn initialise_library(guard: &ReentrantMutexGuard<'static, RefCell>) { + if !guard.borrow().deref() { + *guard.borrow_mut() = true; + set_error_defaults(); } - CACHE.with(|cache| { - if cache.get() { - return Ok(()); - } - match SPICE_THREAD_ID.set(thread::current()) { - Ok(_) => { - cache.set(true); - set_error_defaults(); - Ok(()) - } - Err(e) => Err(SpiceThreadError(e)), - } - }) } -/// Error returned from [try_acquire_thread()]. +#[derive(Debug)] +pub struct SpiceLock(ReentrantMutexGuard<'static, RefCell>); + +/// Error returned from [try_with_spice_lock()]. #[derive(Debug, Clone, Error)] -#[cfg_attr(not(test), error("SPICE is already in use by another thread"))] -#[cfg_attr(test, error("SPICE is already in use by another thread. When running unit tests you will likely need to use the `--test-threads=1` argument"))] -pub struct SpiceThreadError(pub Thread); +#[cfg_attr(not(test), error("SPICE is already in use by another thread. If multi-threaded use is intentional wrap the call using `with_spice_lock()`."))] +#[cfg_attr(test, error("SPICE is already in use by another thread. When running unit tests you will likely need to use the `--test-threads=1` argument."))] +pub struct SpiceLockError; #[cfg(test)] mod tests { - use super::*; use crate::data::furnish; use std::path::PathBuf; use std::sync::Once; @@ -77,20 +88,4 @@ mod tests { furnish(data_dir.join("testkernel.txt").to_string_lossy()).unwrap(); }); } - - #[test] - fn test_acquire_thread() { - try_acquire_thread().unwrap(); - try_acquire_thread().unwrap(); - } - - #[test] - fn test_acquire_thread_different_thread() { - try_acquire_thread().unwrap(); - std::thread::spawn(|| { - try_acquire_thread().expect_err("Should be unable to use on another thread") - }) - .join() - .unwrap(); - } } diff --git a/cspice/src/spk.rs b/cspice/src/spk.rs index 9d6545d..59d3998 100644 --- a/cspice/src/spk.rs +++ b/cspice/src/spk.rs @@ -5,7 +5,7 @@ use crate::error::get_last_error; use crate::string::StringParam; use crate::time::Et; use crate::vector::Vector3D; -use crate::{spice_unsafe, Error}; +use crate::{with_spice_lock_or_panic, Error}; use cspice_sys::{spkez_c, spkezp_c, spkezr_c, spkpos_c, SpiceDouble}; use derive_more::Into; @@ -42,21 +42,23 @@ where R: Into>, O: Into>, { - let mut position = [0.0f64; 3]; - let mut light_time = 0.0; - spice_unsafe!({ - spkpos_c( - target.into().as_mut_ptr(), - et.0, - reference_frame.into().as_mut_ptr(), - aberration_correction.as_spice_char(), - observing_body.into().as_mut_ptr(), - position.as_mut_ptr(), - &mut light_time, - ) - }); - get_last_error()?; - Ok((position.into(), light_time)) + with_spice_lock_or_panic(|| { + let mut position = [0.0f64; 3]; + let mut light_time = 0.0; + unsafe { + spkpos_c( + target.into().as_mut_ptr(), + et.0, + reference_frame.into().as_mut_ptr(), + aberration_correction.as_spice_char(), + observing_body.into().as_mut_ptr(), + position.as_mut_ptr(), + &mut light_time, + ) + }; + get_last_error()?; + Ok((position.into(), light_time)) + }) } /// Return the state (position and velocity) of a target body @@ -74,21 +76,23 @@ pub fn easy_reader<'r, R>( where R: Into>, { - let mut pos_vel: [SpiceDouble; 6] = [0.0; 6]; - let mut light_time = 0.0; - spice_unsafe!({ - spkez_c( - target, - et.0, - reference_frame.into().as_mut_ptr(), - aberration_correction.as_spice_char(), - observing_body, - pos_vel.as_mut_ptr(), - &mut light_time, - ) - }); - get_last_error()?; - Ok((State::from(pos_vel), light_time)) + with_spice_lock_or_panic(|| { + let mut pos_vel: [SpiceDouble; 6] = [0.0; 6]; + let mut light_time = 0.0; + unsafe { + spkez_c( + target, + et.0, + reference_frame.into().as_mut_ptr(), + aberration_correction.as_spice_char(), + observing_body, + pos_vel.as_mut_ptr(), + &mut light_time, + ) + }; + get_last_error()?; + Ok((State::from(pos_vel), light_time)) + }) } /// Return the position of a target body relative to an observing @@ -106,21 +110,23 @@ pub fn easy_position<'r, R>( where R: Into>, { - let mut position = [0.0f64; 3]; - let mut light_time = 0.0; - spice_unsafe!({ - spkezp_c( - target, - et.0, - reference_frame.into().as_mut_ptr(), - aberration_correction.as_spice_char(), - observing_body, - position.as_mut_ptr(), - &mut light_time, - ) - }); - get_last_error()?; - Ok((position.into(), light_time)) + with_spice_lock_or_panic(|| { + let mut position = [0.0f64; 3]; + let mut light_time = 0.0; + unsafe { + spkezp_c( + target, + et.0, + reference_frame.into().as_mut_ptr(), + aberration_correction.as_spice_char(), + observing_body, + position.as_mut_ptr(), + &mut light_time, + ) + }; + get_last_error()?; + Ok((position.into(), light_time)) + }) } /// Return the state (position and velocity) of a target body @@ -140,21 +146,23 @@ where R: Into>, O: Into>, { - let mut pos_vel = [0.0f64; 6]; - let mut light_time = 0.0; - spice_unsafe!({ - spkezr_c( - target.into().as_mut_ptr(), - et.0, - reference_frame.into().as_mut_ptr(), - aberration_correction.as_spice_char(), - observing_body.into().as_mut_ptr(), - pos_vel.as_mut_ptr(), - &mut light_time, - ) - }); - get_last_error()?; - Ok((State::from(pos_vel), light_time)) + with_spice_lock_or_panic(|| { + let mut pos_vel = [0.0f64; 6]; + let mut light_time = 0.0; + unsafe { + spkezr_c( + target.into().as_mut_ptr(), + et.0, + reference_frame.into().as_mut_ptr(), + aberration_correction.as_spice_char(), + observing_body.into().as_mut_ptr(), + pos_vel.as_mut_ptr(), + &mut light_time, + ) + }; + get_last_error()?; + Ok((State::from(pos_vel), light_time)) + }) } #[cfg(test)] diff --git a/cspice/src/string.rs b/cspice/src/string.rs index de95687..436d925 100644 --- a/cspice/src/string.rs +++ b/cspice/src/string.rs @@ -22,7 +22,7 @@ impl Debug for SpiceString { impl Display for SpiceString { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.write_str(&*self.as_str()) + f.write_str(&self.as_str()) } } @@ -117,7 +117,7 @@ impl Debug for SpiceStr<'_> { impl Display for SpiceStr<'_> { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.write_str(&*self.as_str()) + f.write_str(&self.as_str()) } } diff --git a/cspice/src/time/date_time.rs b/cspice/src/time/date_time.rs index 05493ab..adde451 100644 --- a/cspice/src/time/date_time.rs +++ b/cspice/src/time/date_time.rs @@ -5,7 +5,7 @@ use crate::time::calendar::Calendar; use crate::time::julian_date::JulianDate; use crate::time::system::System; use crate::time::{set_default_calendar, Et}; -use crate::{spice_unsafe, SpiceString}; +use crate::{with_spice_lock_or_panic, SpiceString}; use cspice_sys::{timdef_c, timout_c, SpiceInt}; use std::fmt::{Display, Formatter}; use std::marker::PhantomData; @@ -55,15 +55,17 @@ impl DateTime { C::short_name() )); let mut buffer = [0; 100]; - spice_unsafe!({ - timout_c( - et.0, - pictur.as_mut_ptr(), - buffer.len() as SpiceInt, - buffer.as_mut_ptr(), - ); + with_spice_lock_or_panic(|| { + unsafe { + timout_c( + et.0, + pictur.as_mut_ptr(), + buffer.len() as SpiceInt, + buffer.as_mut_ptr(), + ); + }; + get_last_error().unwrap(); }); - get_last_error().unwrap(); let output = SpiceStr::from_buffer(&buffer); let cow = output.as_str(); let split: Vec<&str> = cow.split(':').collect(); @@ -95,44 +97,46 @@ impl From> for Et { /// Convert a DateTime to Ephemeris Time (TDB) #[inline] fn from(dt: DateTime) -> Self { - // Get default calendar setting - let mut original_cal = [0; 12]; - spice_unsafe!({ - timdef_c( - GET.as_mut_ptr(), - CALENDAR.as_mut_ptr(), - original_cal.len() as SpiceInt, - original_cal.as_mut_ptr(), - ); - }); - get_last_error().unwrap(); - let year = if dt.year > 0 { - dt.year.to_string() - } else { - format!("{} BC", dt.year.abs() + 1) - }; - let date = format!( - "{year}-{}-{} {}:{}:{} {}", - dt.month, - dt.day, - dt.hour, - dt.minute, - dt.second, - dt.system.meta_marker(), - ); - set_default_calendar::(); - let et = Et::from_string(date).unwrap(); - // Restore default calendar - spice_unsafe!({ - timdef_c( - SET.as_mut_ptr(), - CALENDAR.as_mut_ptr(), - 0, - original_cal.as_mut_ptr(), + with_spice_lock_or_panic(|| { + // Get default calendar setting + let mut original_cal = [0; 12]; + unsafe { + timdef_c( + GET.as_mut_ptr(), + CALENDAR.as_mut_ptr(), + original_cal.len() as SpiceInt, + original_cal.as_mut_ptr(), + ); + }; + get_last_error().unwrap(); + let year = if dt.year > 0 { + dt.year.to_string() + } else { + format!("{} BC", dt.year.abs() + 1) + }; + let date = format!( + "{year}-{}-{} {}:{}:{} {}", + dt.month, + dt.day, + dt.hour, + dt.minute, + dt.second, + dt.system.meta_marker(), ); - }); - get_last_error().unwrap(); - et + set_default_calendar::(); + let et = Et::from_string(date).unwrap(); + // Restore default calendar + unsafe { + timdef_c( + SET.as_mut_ptr(), + CALENDAR.as_mut_ptr(), + 0, + original_cal.as_mut_ptr(), + ); + }; + get_last_error().unwrap(); + et + }) } } diff --git a/cspice/src/time/julian_date.rs b/cspice/src/time/julian_date.rs index ce27139..0abc6bd 100644 --- a/cspice/src/time/julian_date.rs +++ b/cspice/src/time/julian_date.rs @@ -1,10 +1,10 @@ use crate::error::get_last_error; -use crate::spice_unsafe; use crate::string::{SpiceStr, SpiceString}; use crate::time::calendar::Calendar; use crate::time::date_time::DateTime; use crate::time::system::System; use crate::time::Et; +use crate::with_spice_lock_or_panic; use cspice_sys::{timout_c, SpiceDouble}; use std::fmt::{Display, Formatter}; use std::marker::PhantomData; @@ -46,15 +46,17 @@ impl From for JulianDate { fn from(et: Et) -> Self { let pictur = SpiceString::from(format!("JULIAND.############# ::{}", S::system_name())); let mut buffer = [0; 40]; - spice_unsafe!({ - timout_c( - et.0, - pictur.as_mut_ptr(), - buffer.len() as i32, - buffer.as_mut_ptr(), - ); + with_spice_lock_or_panic(|| { + unsafe { + timout_c( + et.0, + pictur.as_mut_ptr(), + buffer.len() as i32, + buffer.as_mut_ptr(), + ) + }; + get_last_error().unwrap(); }); - get_last_error().unwrap(); Self::new(SpiceStr::from_buffer(&buffer).as_str().parse().unwrap()) } } diff --git a/cspice/src/time/mod.rs b/cspice/src/time/mod.rs index 81f48dd..84f43bf 100644 --- a/cspice/src/time/mod.rs +++ b/cspice/src/time/mod.rs @@ -11,7 +11,7 @@ pub use julian_date::JulianDate; use crate::common::{CALENDAR, SET}; use crate::error::get_last_error; use crate::string::{SpiceString, StringParam}; -use crate::{spice_unsafe, Error}; +use crate::{with_spice_lock_or_panic, Error}; use calendar::Calendar; use cspice_sys::{str2et_c, timdef_c, timout_c, SpiceDouble, SpiceInt}; use derive_more::{From, Into}; @@ -43,15 +43,17 @@ impl Et { out_length: usize, ) -> Result { let mut buffer = vec![0; out_length]; - spice_unsafe!({ - timout_c( - self.0, - pictur.into().as_mut_ptr(), - buffer.len() as SpiceInt, - buffer.as_mut_ptr(), - ); - }); - get_last_error()?; + with_spice_lock_or_panic(|| { + unsafe { + timout_c( + self.0, + pictur.into().as_mut_ptr(), + buffer.len() as SpiceInt, + buffer.as_mut_ptr(), + ); + }; + get_last_error() + })?; Ok(SpiceString::from_buffer(buffer).to_string()) } @@ -60,12 +62,14 @@ impl Et { /// See [str2et_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/str2et_c.html) #[inline] pub fn from_string<'p, P: Into>>(string: P) -> Result { - let mut output = 0f64; - spice_unsafe!({ - str2et_c(string.into().as_mut_ptr(), &mut output); - }); - get_last_error()?; - Ok(Self(output)) + with_spice_lock_or_panic(|| { + let mut output = 0f64; + unsafe { + str2et_c(string.into().as_mut_ptr(), &mut output); + }; + get_last_error()?; + Ok(Self(output)) + }) } } @@ -75,15 +79,17 @@ impl Et { #[inline] pub fn set_default_calendar() { let name = SpiceString::from(C::name()); - spice_unsafe!({ - timdef_c( - SET.as_mut_ptr(), - CALENDAR.as_mut_ptr(), - 0, - name.as_mut_ptr(), - ); - }); - get_last_error().unwrap(); + with_spice_lock_or_panic(|| { + unsafe { + timdef_c( + SET.as_mut_ptr(), + CALENDAR.as_mut_ptr(), + 0, + name.as_mut_ptr(), + ); + }; + get_last_error().unwrap(); + }) } #[cfg(test)] diff --git a/cspice/src/vector.rs b/cspice/src/vector.rs index 3c7dde8..8465f0a 100644 --- a/cspice/src/vector.rs +++ b/cspice/src/vector.rs @@ -2,7 +2,7 @@ //! //! See [Performing simple operations on 3D vectors](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/info/mostused.html#U) use crate::coordinates::Rectangular; -use crate::spice_unsafe; +use crate::with_spice_lock_or_panic; use cspice_sys::{vsep_c, SpiceDouble}; use derive_more::{Deref, DerefMut, From, Into}; @@ -16,7 +16,7 @@ impl Vector3D { /// /// See [vsep_c](https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/vsep_c.html) pub fn separation_angle(&self, other: &Vector3D) -> SpiceDouble { - spice_unsafe!({ + with_spice_lock_or_panic(|| unsafe { vsep_c( self.as_ptr() as *mut SpiceDouble, other.as_ptr() as *mut SpiceDouble,