1use crate::c::{
23 SpiceBoolean, SpiceCell, SpiceChar, SpiceDLADescr, SpiceDSKDescr, SpiceDouble, SpiceEKAttDsc,
24 SpiceEKSegSum, SpiceEllipse, SpiceInt, SpicePlane,
25};
26use crate::MAX_LEN_OUT;
27use std::ffi::{CStr, CString};
28
29pub type UdFunc = unsafe extern "C" fn(x: SpiceDouble, value: *mut SpiceDouble);
42
43pub type UdFuns = UdFunc;
45
46pub type UdFunb =
48 unsafe extern "C" fn(udfuns: Option<UdFuns>, x: SpiceDouble, xbool: *mut SpiceBoolean);
49
50pub type UdStep = unsafe extern "C" fn(et: SpiceDouble, step: *mut SpiceDouble);
52
53pub type UdRefn = unsafe extern "C" fn(
55 t1: SpiceDouble,
56 t2: SpiceDouble,
57 s1: SpiceBoolean,
58 s2: SpiceBoolean,
59 t: *mut SpiceDouble,
60);
61
62pub type UdRepi =
64 unsafe extern "C" fn(cnfine: *mut SpiceCell, srcpre: *mut SpiceChar, srcsuf: *mut SpiceChar);
65
66pub type UdRepu = unsafe extern "C" fn(ivbeg: SpiceDouble, ivend: SpiceDouble, et: SpiceDouble);
68
69pub type UdRepf = unsafe extern "C" fn();
71
72pub type UdBail = unsafe extern "C" fn() -> SpiceBoolean;
74
75const INLINE_IN: usize = 64;
82
83pub struct Buffer<const N: usize> {
90 inline: [SpiceChar; N],
91 heap: Option<Vec<SpiceChar>>,
93}
94
95impl<const N: usize> Buffer<N> {
96 pub fn from_text(value: &str) -> Self {
105 let bytes = value.as_bytes();
106 if bytes.len() < N && !bytes.contains(&0) {
107 let mut inline = [0; N];
108 for (target, byte) in inline.iter_mut().zip(bytes) {
109 *target = *byte as SpiceChar;
110 }
111 return Self { inline, heap: None };
112 }
113
114 let owned = to_cstring(value);
115 let heap = owned
116 .as_bytes_with_nul()
117 .iter()
118 .map(|&byte| byte as SpiceChar)
119 .collect();
120 Self {
121 inline: [0; N],
122 heap: Some(heap),
123 }
124 }
125
126 pub fn with_len(len: usize) -> Self {
128 let len = len.max(1);
129 if len <= N {
130 return Self {
131 inline: [0; N],
132 heap: None,
133 };
134 }
135 Self {
136 inline: [0; N],
137 heap: Some(vec![0; len]),
138 }
139 }
140
141 #[inline]
143 pub fn as_mut_ptr(&mut self) -> *mut SpiceChar {
144 match &mut self.heap {
145 Some(heap) => heap.as_mut_ptr(),
146 None => self.inline.as_mut_ptr(),
147 }
148 }
149
150 pub fn into_string(self) -> String {
152 match &self.heap {
153 Some(heap) => from_cbuf(heap),
154 None => from_cbuf(&self.inline),
155 }
156 }
157}
158
159pub trait SpiceArg {
167 type Owned;
169
170 type Raw;
172
173 fn own(self) -> Self::Owned;
175
176 fn raw(owned: &mut Self::Owned) -> Self::Raw;
178}
179
180pub struct In<T: SpiceArg> {
187 owned: T::Owned,
188}
189
190impl<T: SpiceArg> In<T> {
191 #[inline]
193 pub fn new(value: T) -> Self {
194 Self { owned: value.own() }
195 }
196
197 #[inline]
199 pub fn raw(&mut self) -> T::Raw {
200 T::raw(&mut self.owned)
201 }
202}
203
204macro_rules! scalar_arg {
206 ($($ty:ty => $raw:ty),* $(,)?) => {$(
207 impl SpiceArg for $ty {
208 type Owned = $ty;
209 type Raw = $raw;
210
211 #[inline]
212 fn own(self) -> Self::Owned {
213 self
214 }
215
216 #[inline]
217 fn raw(owned: &mut Self::Owned) -> Self::Raw {
218 *owned as $raw
219 }
220 }
221 )*};
222}
223
224scalar_arg! {
225 f32 => SpiceDouble,
226 f64 => SpiceDouble,
227 i8 => SpiceInt,
228 i16 => SpiceInt,
229 i32 => SpiceInt,
230 i64 => SpiceInt,
231 isize => SpiceInt,
232 u8 => SpiceInt,
233 u16 => SpiceInt,
234 u32 => SpiceInt,
235 u64 => SpiceInt,
236 usize => SpiceInt,
237 bool => SpiceBoolean,
238}
239
240macro_rules! array_arg {
242 ($($ty:ty => $raw:ty),* $(,)?) => {$(
243 impl<const N: usize> SpiceArg for [$ty; N] {
244 type Owned = [$ty; N];
245 type Raw = *mut $raw;
246
247 #[inline]
248 fn own(self) -> Self::Owned {
249 self
250 }
251
252 #[inline]
253 fn raw(owned: &mut Self::Owned) -> Self::Raw {
254 owned.as_mut_ptr()
255 }
256 }
257
258 impl<const M: usize, const N: usize> SpiceArg for [[$ty; N]; M] {
259 type Owned = [[$ty; N]; M];
260 type Raw = *mut $raw;
261
262 #[inline]
263 fn own(self) -> Self::Owned {
264 self
265 }
266
267 #[inline]
268 fn raw(owned: &mut Self::Owned) -> Self::Raw {
269 owned.as_mut_ptr().cast()
270 }
271 }
272 )*};
273}
274
275array_arg! {
276 f64 => SpiceDouble,
277 i32 => SpiceInt,
278}
279
280impl<'a, T> SpiceArg for &'a [T] {
282 type Owned = &'a [T];
283 type Raw = *const T;
284
285 #[inline]
286 fn own(self) -> Self::Owned {
287 self
288 }
289
290 #[inline]
291 fn raw(owned: &mut Self::Owned) -> Self::Raw {
292 owned.as_ptr()
293 }
294}
295
296impl<'a, T> SpiceArg for &'a mut [T] {
297 type Owned = &'a mut [T];
298 type Raw = *mut T;
299
300 #[inline]
301 fn own(self) -> Self::Owned {
302 self
303 }
304
305 #[inline]
306 fn raw(owned: &mut Self::Owned) -> Self::Raw {
307 owned.as_mut_ptr()
308 }
309}
310
311impl SpiceArg for char {
315 type Owned = char;
316 type Raw = SpiceChar;
317
318 #[inline]
319 fn own(self) -> Self::Owned {
320 self
321 }
322
323 #[inline]
324 fn raw(owned: &mut Self::Owned) -> Self::Raw {
325 *owned as u32 as SpiceChar
326 }
327}
328
329impl SpiceArg for &str {
330 type Owned = Buffer<INLINE_IN>;
331 type Raw = *mut SpiceChar;
332
333 #[inline]
334 fn own(self) -> Self::Owned {
335 Buffer::from_text(self)
336 }
337
338 #[inline]
339 fn raw(owned: &mut Self::Owned) -> Self::Raw {
340 owned.as_mut_ptr()
341 }
342}
343
344impl SpiceArg for &String {
345 type Owned = Buffer<INLINE_IN>;
346 type Raw = *mut SpiceChar;
347
348 #[inline]
349 fn own(self) -> Self::Owned {
350 Buffer::from_text(self)
351 }
352
353 #[inline]
354 fn raw(owned: &mut Self::Owned) -> Self::Raw {
355 owned.as_mut_ptr()
356 }
357}
358
359impl SpiceArg for String {
360 type Owned = Buffer<INLINE_IN>;
361 type Raw = *mut SpiceChar;
362
363 #[inline]
364 fn own(self) -> Self::Owned {
365 Buffer::from_text(&self)
366 }
367
368 #[inline]
369 fn raw(owned: &mut Self::Owned) -> Self::Raw {
370 owned.as_mut_ptr()
371 }
372}
373
374macro_rules! struct_arg {
376 ($($ty:ty),* $(,)?) => {$(
377 impl SpiceArg for $ty {
378 type Owned = $ty;
379 type Raw = *mut $ty;
380
381 #[inline]
382 fn own(self) -> Self::Owned {
383 self
384 }
385
386 #[inline]
387 fn raw(owned: &mut Self::Owned) -> Self::Raw {
388 owned as *mut $ty
389 }
390 }
391 )*};
392}
393
394struct_arg!(SpiceDLADescr, SpiceDSKDescr, SpicePlane, SpiceEllipse);
395
396pub trait SpiceRet: Sized {
404 type Buf;
406
407 type Raw;
409
410 fn buf() -> Self::Buf;
412
413 fn buf_with_len(len: usize) -> Self::Buf {
415 let _ = len;
416 Self::buf()
417 }
418
419 fn raw(buf: &mut Self::Buf) -> Self::Raw;
421
422 fn get(buf: Self::Buf) -> Self;
424}
425
426pub struct Out<T: SpiceRet> {
430 buf: T::Buf,
431}
432
433impl<T: SpiceRet> Out<T> {
434 #[inline]
436 pub fn new() -> Self {
437 Self { buf: T::buf() }
438 }
439
440 #[inline]
442 pub fn with_len(len: usize) -> Self {
443 Self {
444 buf: T::buf_with_len(len),
445 }
446 }
447
448 #[inline]
450 pub fn raw(&mut self) -> T::Raw {
451 T::raw(&mut self.buf)
452 }
453
454 #[inline]
456 pub fn get(self) -> T {
457 T::get(self.buf)
458 }
459}
460
461impl<T: SpiceRet> Default for Out<T> {
462 fn default() -> Self {
463 Self::new()
464 }
465}
466
467macro_rules! scalar_ret {
469 ($($ty:ty => $raw:ty, $zero:expr, $read:expr);* $(;)?) => {$(
470 impl SpiceRet for $ty {
471 type Buf = $raw;
472 type Raw = *mut $raw;
473
474 #[inline]
475 fn buf() -> Self::Buf {
476 $zero
477 }
478
479 #[inline]
480 fn raw(buf: &mut Self::Buf) -> Self::Raw {
481 buf as *mut $raw
482 }
483
484 #[inline]
485 fn get(buf: Self::Buf) -> Self {
486 #[allow(clippy::redundant_closure_call)]
487 ($read)(buf)
488 }
489 }
490 )*};
491}
492
493scalar_ret! {
494 f64 => SpiceDouble, 0.0, |value| value;
495 i32 => SpiceInt, 0, |value| value;
496 bool => SpiceBoolean, 0, |value: SpiceBoolean| value != 0;
497}
498
499macro_rules! array_ret {
501 ($($ty:ty => $raw:ty),* $(,)?) => {$(
502 impl<const N: usize> SpiceRet for [$ty; N] {
503 type Buf = [$ty; N];
504 type Raw = *mut $raw;
505
506 #[inline]
507 fn buf() -> Self::Buf {
508 [<$ty>::default(); N]
509 }
510
511 #[inline]
512 fn raw(buf: &mut Self::Buf) -> Self::Raw {
513 buf.as_mut_ptr()
514 }
515
516 #[inline]
517 fn get(buf: Self::Buf) -> Self {
518 buf
519 }
520 }
521
522 impl<const M: usize, const N: usize> SpiceRet for [[$ty; N]; M] {
523 type Buf = [[$ty; N]; M];
524 type Raw = *mut $raw;
525
526 #[inline]
527 fn buf() -> Self::Buf {
528 [[<$ty>::default(); N]; M]
529 }
530
531 #[inline]
532 fn raw(buf: &mut Self::Buf) -> Self::Raw {
533 buf.as_mut_ptr().cast()
534 }
535
536 #[inline]
537 fn get(buf: Self::Buf) -> Self {
538 buf
539 }
540 }
541 )*};
542}
543
544array_ret! {
545 f64 => SpiceDouble,
546 i32 => SpiceInt,
547}
548
549impl SpiceRet for String {
550 type Buf = Buffer<MAX_LEN_OUT>;
551 type Raw = *mut SpiceChar;
552
553 #[inline]
554 fn buf() -> Self::Buf {
555 Buffer::with_len(MAX_LEN_OUT)
556 }
557
558 #[inline]
559 fn buf_with_len(len: usize) -> Self::Buf {
560 Buffer::with_len(len)
561 }
562
563 #[inline]
564 fn raw(buf: &mut Self::Buf) -> Self::Raw {
565 buf.as_mut_ptr()
566 }
567
568 #[inline]
569 fn get(buf: Self::Buf) -> Self {
570 buf.into_string()
571 }
572}
573
574macro_rules! struct_ret {
576 ($($ty:ty),* $(,)?) => {$(
577 impl SpiceRet for $ty {
578 type Buf = $ty;
579 type Raw = *mut $ty;
580
581 #[inline]
582 fn buf() -> Self::Buf {
583 unsafe { std::mem::zeroed() }
585 }
586
587 #[inline]
588 fn raw(buf: &mut Self::Buf) -> Self::Raw {
589 buf as *mut $ty
590 }
591
592 #[inline]
593 fn get(buf: Self::Buf) -> Self {
594 buf
595 }
596 }
597 )*};
598}
599
600struct_ret!(
601 SpiceDLADescr,
602 SpiceDSKDescr,
603 SpicePlane,
604 SpiceEllipse,
605 SpiceEKAttDsc,
606 SpiceEKSegSum,
607);
608
609pub trait SpiceReturn {
617 type Raw;
619
620 unsafe fn from_c(raw: Self::Raw) -> Self;
627}
628
629impl SpiceReturn for f64 {
630 type Raw = SpiceDouble;
631
632 #[inline]
633 unsafe fn from_c(raw: Self::Raw) -> Self {
634 raw
635 }
636}
637
638impl SpiceReturn for i32 {
639 type Raw = SpiceInt;
640
641 #[inline]
642 unsafe fn from_c(raw: Self::Raw) -> Self {
643 raw
644 }
645}
646
647impl SpiceReturn for bool {
648 type Raw = SpiceBoolean;
649
650 #[inline]
651 unsafe fn from_c(raw: Self::Raw) -> Self {
652 raw != 0
653 }
654}
655
656impl SpiceReturn for String {
657 type Raw = *mut SpiceChar;
658
659 #[inline]
660 unsafe fn from_c(raw: Self::Raw) -> Self {
661 if raw.is_null() {
662 return String::new();
663 }
664 unsafe { CStr::from_ptr(raw) }
667 .to_string_lossy()
668 .into_owned()
669 }
670}
671
672pub fn to_cstring<S: AsRef<str>>(string: S) -> CString {
685 let string = string.as_ref();
686 CString::new(string).unwrap_or_else(|_| {
687 panic!("a string passed to CSPICE must not contain a null byte, got {string:?}")
688 })
689}
690
691pub fn from_cbuf(buf: &[SpiceChar]) -> String {
698 let bytes = buf.iter().map(|&byte| byte as u8).collect::<Vec<u8>>();
699 let end = bytes
700 .iter()
701 .position(|&byte| byte == 0)
702 .unwrap_or(bytes.len());
703 String::from_utf8_lossy(&bytes[..end])
704 .trim_end()
705 .to_string()
706}
707
708pub fn to_strided<S: AsRef<str>>(values: &[S]) -> (Vec<SpiceChar>, usize) {
714 let stride = values
715 .iter()
716 .map(|value| value.as_ref().len() + 1)
717 .max()
718 .unwrap_or(1);
719
720 let mut buffer = vec![0 as SpiceChar; values.len().max(1) * stride];
721 for (index, value) in values.iter().enumerate() {
722 let slot = &mut buffer[index * stride..(index + 1) * stride];
723 for (target, byte) in slot.iter_mut().zip(value.as_ref().as_bytes()) {
724 *target = *byte as SpiceChar;
725 }
726 }
727 (buffer, stride)
728}
729
730pub fn from_strided(buffer: &[SpiceChar], stride: usize, count: usize) -> Vec<String> {
734 (0..count)
735 .map(|index| from_cbuf(&buffer[index * stride..(index + 1) * stride]))
736 .collect()
737}
738
739pub(crate) const CELL_CTRLSZ: usize = crate::c::SPICE_CELL_CTRLSZ as usize;
741
742impl<'a, T: crate::core::cell::CellItem> SpiceArg for &'a mut crate::core::cell::Cell<T> {
744 type Owned = &'a mut crate::core::cell::Cell<T>;
745 type Raw = *mut SpiceCell;
746
747 #[inline]
748 fn own(self) -> Self::Owned {
749 self
750 }
751
752 #[inline]
753 fn raw(owned: &mut Self::Owned) -> Self::Raw {
754 owned.as_mut_ptr()
755 }
756}