Skip to content

Commit 5ef4188

Browse files
committed
Add 'SpiceLock' example to README
1 parent c04b90e commit 5ef4188

File tree

2 files changed

+54
-1
lines changed

2 files changed

+54
-1
lines changed

rust-spice/README.md

+30
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,34 @@ spice::unload("hera/kernels/mk/hera_study_PO_EMA_2024.tm");
7878

7979
You can look for some inspirations in the [core tests][core tests link].
8080

81+
## Multi-threaded usage
82+
83+
CSPICE itself contains massive amounts of shared mutable state and is thus not thread-safe - concurrent
84+
calls to any SPICE functions will almost always lead to crashes. To prevent this, if you need
85+
to call SPICE functions from multiple threads, this crate provides a thread-safe API with the `lock`
86+
feature. When enabled, the API is exposed in the form of associated functions on a guard singleton
87+
`SpiceLock`, which is `!Sync + Send`. You can then only share this singleton and thus the methods it
88+
provides between threads using a `Mutex`, preventing concurrent API usage.
89+
90+
The lock exposes the [neat][neat link] versions of functions where available, and the [raw][raw link] versions for the rest.
91+
For functions which have neither, you will have to use the unsafe (and unguarded) direct C bindings.
92+
Just make sure you have the lock before calling them.
93+
94+
```rust
95+
use spice::SpiceLock;
96+
97+
// `try_acquire` will return `Err` if a lock already exists
98+
let sl = SpiceLock::try_acquire().unwrap();
99+
100+
// SPICE functions are now associated functions of the lock with a `&self` arg
101+
let mut kernel = sl.furnsh("hera/kernels/mk/hera_study_PO_EMA_2024.tm");
102+
103+
let et = sl.str2et("2027-MAR-23 16:00:00");
104+
let (position, light_time) = sl.spkpos("DIMORPHOS", et, "J2000", "NONE", "SUN");
105+
106+
sl.unload("hera/kernels/mk/hera_study_PO_EMA_2024.tm");
107+
```
108+
81109
## In development
82110

83111
Developing an idiomatic interface for Spice in Rust takes time, and not all
@@ -163,6 +191,8 @@ Licensed under the [Apache License, Version 2.0][license link].
163191
[cspice install link]: https://naif.jpl.nasa.gov/naif/toolkit_C.html
164192
[cspice-sys link]: https://github.com/jacob-pro/cspice-rs/tree/master/cspice-sys
165193
[config doc]: https://doc.rust-lang.org/cargo/reference/config.html
194+
[raw link]: https://docs.rs/rust-spice/latest/spice/core/raw/index.html
195+
[neat link]: https://docs.rs/rust-spice/latest/spice/core/neat/index.html
166196

167197
[s-rah url]: https://github.com/s-rah
168198
[PR 2]: https://github.com/GregoireHENRY/rust-spice/pull/2

rust-spice/tests/core/mod.rs

+24-1
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,29 @@ pub mod lock_tests {
466466
}
467467
#[test]
468468
#[serial]
469+
fn spkezr() {
470+
spice::furnsh("hera/kernels/mk/hera_study_PO_EMA_2024.tm");
471+
472+
// an arbitrary time
473+
let et = spice::str2et("2021-01-06 09:36:09.1825432 TDB");
474+
475+
// sun in relation to ssb
476+
let (sun_ssb_posvec, _sun_ssb_lt) = spice::spkezr("sun", et, "j2000", "none", "ssb");
477+
// earth in relation to ssb
478+
let (earth_ssb_posvec, _earth_ssb_lt) = spice::spkezr("earth", et, "j2000", "none", "ssb");
479+
// earth in relation to sun
480+
let (earth_sun_posvec, _earth_sun_ly) = spice::spkezr("earth", et, "j2000", "none", "sun");
481+
482+
// Quick check that the (Sun relative) earth velocity vectors are the same regardless of whether we
483+
// calculate them indirectly from SB or directly compared to the Sun
484+
assert_eq!(earth_ssb_posvec[3] - sun_ssb_posvec[3], earth_sun_posvec[3]);
485+
assert_eq!(earth_ssb_posvec[4] - sun_ssb_posvec[4], earth_sun_posvec[4]);
486+
assert_eq!(earth_ssb_posvec[5] - sun_ssb_posvec[5], earth_sun_posvec[5]);
487+
488+
spice::unload("hera/kernels/mk/hera_study_PO_EMA_2024.tm");
489+
}
490+
#[test]
491+
#[serial]
469492
fn multiple_threads() {
470493
use std::sync::{Arc, Mutex};
471494
use std::thread;
@@ -479,7 +502,7 @@ pub mod lock_tests {
479502
let mut children = Vec::with_capacity(n_children);
480503

481504
for _ in 0..n_children {
482-
let sl = Arc::clone(&sl);
505+
let mut sl = Arc::clone(&sl);
483506
children.push(thread::spawn(move || {
484507
for _ in 0..10 {
485508
// If these calls were not guarded by the lock, they could lead to data races and UB

0 commit comments

Comments
 (0)