1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
//! Pure Rust port of the SPICE Toolkit for space geometry.
//!
//! This implementation is fully memory-safe and thread-safe,
//! and does not depend on any external C/FORTRAN libraries.
//! It provides nearly the entire SPICELIB API.
//! The code has been mechanically [translated](https://github.com/zaynar/f2rust)
//! from the FORTRAN version of the SPICE Toolkit into Rust.
//!
//! It is completely unofficial, unsupported, and not heavily tested
//! (though it does pass the Toolkit's regression tests so it's probably
//! not too bad). Use at your own risk.
//!
//! Users of this library should not expect any support from NAIF.
//! Use the [GitHub project](https://github.com/zaynar/rsspice)
//! for any issues or queries.
//!
//! # Usage example
//!
//! This example demonstrates the general design:
//!
//! ```no_run
//! use rsspice::*;
//!
//! const TIMFMT: &str = "YYYY MON DD HR:MN:SC.###### (TDB)::TDB";
//! const MAXWIN: usize = 2 * 100;
//!
//! // Find solar eclipses as seen from the center of the Earth.
//! fn main() -> Result<()> {
//! let mut spice = SpiceContext::new();
//!
//! spice.furnsh("gfoclt_ex1.tm")?;
//!
//! let mut confine = Cell::with_capacity(2);
//! let mut result = Cell::with_capacity(MAXWIN);
//!
//! let et0 = spice.str2et("2027 JAN 01 00:00:00 TDB")?;
//! let et1 = spice.str2et("2029 JAN 01 00:00:00 TDB")?;
//!
//! spice.wninsd(et0, et1, &mut confine)?;
//!
//! spice.gfoclt(
//! "ANY",
//! "MOON", "ellipsoid", "IAU_MOON",
//! "SUN", "ellipsoid", "IAU_SUN",
//! "LT", "EARTH", 180.0, &confine,
//! &mut result,
//! )?;
//!
//! for i in 1..=spice.wncard(&result)? {
//! let (left, right) = spice.wnfetd(&result, i)?;
//! println!(
//! "Interval {i}: {} - {}",
//! spice.timout(left, TIMFMT)?,
//! spice.timout(right, TIMFMT)?
//! );
//! }
//!
//! Ok(())
//! }
//! ```
//!
//! (See more [examples](https://github.com/zaynar/rsspice/tree/main/examples)
//! and [lessons](https://github.com/zaynar/rsspice/tree/main/lessons).)
//!
//! The [`SpiceContext`] object encapsulates all the SPICE state, such as loaded
//! kernels. There is no process-wide global state, so you can run multiple
//! `SpiceContext`s concurrently in separate threads.
//!
//! There is a 1:1 mapping between functions in the FORTRAN API and
//! in the Rust API, so you can refer to the extensive FORTRAN documentation
//! and adapt its examples relatively easily.
//! (The API docs and [required reading](required_reading) are mirrored in rustdoc.
//! Further tutorials and lessons are available from [NAIF](https://naif.jpl.nasa.gov/).)
//!
//! Arguments are not exactly a 1:1 mapping -- we try to turn them into more idiomatic Rust types.
//! Output arguments are typically mapped onto return values.
//! SPICE errors are mapped onto Rust's error system, so they can
//! be easily handled with `Result` and `?`.
//!
//! FORTRAN arrays are typically indexed from 1, not 0.
//! Functions like `wnfetd` similarly start counting from 1; we do not attempt
//! any automatic translation of indexes.
//! (This differs from the CSPICE translation, and wrappers around CSPICE,
//! which count from 0.)
//!
//! There is a [`Cell`] type for SPICE cells (including windows and sets), as they are
//! particularly awkward to handle with standard Rust types.
//! But `Cell` only provides very basic functionality;
//! this library is not attempting to provide a higher-level API than the original SPICELIB.
//!
//! # Background
//!
//! SPICE is "an observation geometry system for space science missions",
//! developed by NASA's
//! [Navigation and Ancillary Information Facility (NAIF)](https://naif.jpl.nasa.gov/).
//!
//! A large amount of geometric data about planets, moons, and spacecraft is
//! publicly available as SPICE data, which can be processed using the SPICE Toolkit
//! software and APIs. NAIF also provides thorough documentation
//! of the system.
//!
//! The SPICE Toolkit is originally developed in FORTRAN, with an official
//! translation to C. Official and unofficial bindings for the C library
//! are available in several other languages (including
//! [rust-spice](https://crates.io/crates/rust-spice)).
//! `rsspice` is an unofficial translation from FORTRAN to Rust, with
//! a number of benefits and drawbacks:
//!
//! * Memory-safe: Rust's bounds-checking ensures that many errors will be
//! detected at runtime and will not result in data corruption.
//!
//! * Thread-safe: The FORTRAN and C implementations depend heavily on global
//! state. `rsspice` moves that state into the `SpiceContext` object, allowing
//! concurrency within a single process.
//! (See [a basic example](https://github.com/zaynar/f2rust/blob/main/rsspice/examples/gfoclt_ex1_mt.rs)
//! using `rayon` to split work across threads.)
//!
//! * Portability: This should work on any platform that Rust supports,
//! including WebAssembly (albeit with some complications around filesystem access).
//!
//! * Much less testing: `rsspice` includes a translation of the TSPICE
//! regression tests, which are reasonably extensive but do not have
//! full coverage of the whole API. There is a higher risk of bugs than
//! in a wrapper around the well-tested FORTRAN/C implementations.
//!
//! # API mapping details
//!
//! The API is mechanically translated from the FORTRAN API, following a number
//! of rules to make it closer to idiomatic Rust.
//! Understanding these can help when reading the FORTRAN documentation.
//!
//! ## Return values
//!
//! Arguments that are documented as "O" are turned into return values.
//! If there are multiple outputs, the function will return a tuple.
//! If one of the outputs is called `FOUND`, it will not be returned explicitly;
//! instead the function will return an `Option<_>`.
//!
//! There are some exceptions, typically array outputs where there is no
//! well-defined maximum size that we can allocate automatically. In this case
//! they are mapped onto `&mut` parameters, and you must initialise the
//! array with an appropriate size before the call.
//!
//! For returned errors, see [`Error`].
//!
//! ## Strings
//!
//! Input strings are `&str`, outputs are typically `String`, mixed input-output
//! and some outputs are `&mut str`.
//!
//! Since FORTRAN 77 does not have dynamic allocation, output strings are
//! allocated at the maximum possible size, and FORTRAN will pad the output
//! with trailing space characters.
//! We trim the trailing spaces before returning a `String`.
//! When using `&mut str`, you are responsible for allocating and trimming:
//!
//! ```
//! # use rsspice::*;
//! # let mut spice = SpiceContext::new();
//! let mut outstr = " ".repeat(80);
//! spice.replwd("Hello world", 1, "Goodbye", &mut outstr);
//! assert_eq!(outstr.trim_ascii_end(), "Goodbye world");
//! ```
//!
//! For FORTRAN `CHARACTER` arrays, see [`CharVec`].
//!
//! FORTRAN 77 barely even understands ASCII, never mind UTF-8.
//! Input strings are simply interpreted as a sequence of bytes.
//! For outputs, the implementation will panic if it ends up producing a non-UTF-8
//! string; this should not happen unless you pass non-ASCII characters into the API
//! (so don't do that).
//!
//! ## Hidden arguments
//!
//! Some functions (like [`GFDIST`](raw::gfdist)) have a `WORK` argument,
//! for temporary data storage.
//! In `rsspice` we dynamically allocate that storage space, so the `WORK`
//! argument and the corresponding `NW` size are removed from the API.
//!
//! ## Omitted functions
//!
//! A small number of functions are excluded from the API, because they are:
//! * Private;
//! * Deprecated/obsolete;
//! * Documented as "DO NOT CALL THIS ROUTINE", or return a `BOGUSENTRY` error;
//! * Redundant with basic Rust functionality, particularly string manipulation.
//!
//! These functions are still available in the [`raw`] API.
//!
//! ## Array arguments
//!
//! 3D vector arguments are typically represented as `&[f64; 3]`.
//! You can conveniently use [`nalgebra`](https://nalgebra.org/) for these:
//!
//! ```
//! # use rsspice::*;
//! # use approx::assert_relative_eq;
//! use nalgebra as na;
//! # let mut spice = SpiceContext::new();
//! let v = na::Vector3::new(1.0, 2.0, 3.0);
//! let r = na::Vector3::from(
//! spice.vrotv(v.as_ref(), &[0.0, 0.0, 1.0], std::f64::consts::FRAC_PI_2));
//! assert_relative_eq!(r, na::Vector3::new(-2.0, 1.0, 3.0));
//! ```
//!
//! If you want to use an `&[f64]` slice (e.g. from a `Vec`), you can use
//! `try_into().unwrap()` (which will panic if the slice is too small):
//!
//! ```
//! # use rsspice::*;
//! # use approx::assert_relative_eq;
//! # let mut spice = SpiceContext::new();
//! let v = [0.0, 1.0, 2.0, 3.0, 4.0];
//! let r = spice.vrotv(&v[1..4].try_into().unwrap(),
//! &[0.0, 0.0, 1.0],
//! std::f64::consts::FRAC_PI_2);
//! assert_relative_eq!(r.as_slice(), [-2.0, 1.0, 3.0].as_slice());
//! ```
//!
//! Matrices are represented as `&[[f64; 3]; 3]` in column-major order
//! (i.e. the first column is stored in memory first, then the second column, etc).
//! This is compatible with `nalgebra::Matrix3`:
//!
//! ```
//! # use rsspice::*;
//! # use approx::assert_relative_eq;
//! use nalgebra as na;
//! # let mut spice = SpiceContext::new();
//! let m = na::Matrix3::new(
//! 0.0, -1.0, 0.0,
//! 0.5, 0.0, 0.0,
//! 0.0, 0.0, 1.0);
//! let mout = na::Matrix3::from(spice.invert(m.as_ref()));
//! assert_relative_eq!(
//! mout,
//! na::Matrix3::new(
//! 0.0, 2.0, 0.0,
//! -1.0, 0.0, 0.0,
//! 0.0, 0.0, 1.0)
//! );
//! ```
//!
//! When reading any FORTRAN example code, note that multidimensional arrays in
//! Rust have indexes in the opposite order to FORTRAN:
//! `M(I, J)` corresponds to `m[j][i]`.
//! But `nalgebra` uses FORTRAN-like indexing: `m[(i, j)]`.
//!
//! # Raw API
//!
//! An alternative version of the API is available in the [`raw`] module.
//! This is a closer match to the FORTRAN API, without the special handling
//! of return values, cells, etc.
//! Each `raw` function reproduces the original FORTRAN API documentation,
//! detailing every input/output argument.
//! You probably shouldn't need to use this API directly,
//! but the documentation is very helpful.
//!
//! # License
//!
//! Much of this crate is derived from the SPICE Toolkit, which is made freely available
//! by NAIF but does not have a clear licensing situation.
//! See [LICENSE.md](https://github.com/zaynar/rsspice/blob/main/LICENSE.md) for details.
//!
//! The non-Toolkit-derived code in this crate is licensed under either of
//!
//! * Apache License, Version 2.0
//! ([LICENSE-APACHE](https://github.com/zaynar/rsspice/blob/main/LICENSE-APACHE)
//! or <http://www.apache.org/licenses/LICENSE-2.0>)
//! * MIT license
//! ([LICENSE-MIT](https://github.com/zaynar/rsspice/blob/main/LICENSE-MIT)
//! or <http://opensource.org/licenses/MIT>)
//!
//! at your option.
pub use *;
/// Collection of reference documents describing the various SPICE subsystems.
///
/// Adapted from <https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/FORTRAN/req/index.html>
pub use craterequired_reading;
/// Lower-level SPICELIB API.
///
/// This module provides the complete SPICELIB API, with a very similar structure to the
/// original FORTRAN API, including the full API reference documentation.
///
/// Most applications should use the [`SpiceContext`] methods instead, as they are
/// slightly more convenient.
///
/// The `raw` functions require the caller to allocate space for outputs and pass them as
/// `&mut` references. `SpiceContext` automatically allocates the space and converts output
/// arguments into return values.
///
/// Most `raw` functions still require a `SpiceContext` instance to store their
/// 'global' state.
pub use crateapi as raw;