1use crate::c::{SpiceChar, SpiceInt};
29use crate::core::ffi::{from_cbuf, to_cstring};
30use crate::MAX_LEN_OUT;
31use std::fmt;
32
33#[cfg(any(feature = "lock", doc))]
34use {crate::core::lock::SpiceLock, spice_derive::impl_for};
35
36#[derive(Clone, Debug, Eq, PartialEq)]
40pub struct Error {
41 pub short: String,
43 pub explain: String,
45 pub long: String,
47 pub traceback: String,
49}
50
51impl fmt::Display for Error {
52 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53 write!(f, "{}", self.short)?;
54 for detail in [&self.explain, &self.long] {
55 if !detail.is_empty() {
56 write!(f, ": {detail}")?;
57 }
58 }
59 if !self.traceback.is_empty() {
60 write!(f, " [{}]", self.traceback)?;
61 }
62 Ok(())
63 }
64}
65
66impl std::error::Error for Error {}
67
68#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
72pub fn failed() -> bool {
73 unsafe { crate::c::failed_c() != 0 }
74}
75
76#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
80pub fn reset() {
81 unsafe { crate::c::reset_c() }
82}
83
84#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
88pub fn getmsg(option: &str) -> String {
89 let option = to_cstring(option);
90 let mut message = vec![0 as SpiceChar; MAX_LEN_OUT];
91 unsafe {
92 crate::c::getmsg_c(
93 option.as_ptr() as *mut SpiceChar,
94 message.len() as SpiceInt,
95 message.as_mut_ptr(),
96 )
97 };
98 from_cbuf(&message)
99}
100
101#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
105pub fn qcktrc() -> String {
106 let mut trace = vec![0 as SpiceChar; MAX_LEN_OUT];
107 unsafe { crate::c::qcktrc_c(trace.len() as SpiceInt, trace.as_mut_ptr()) };
108 from_cbuf(&trace)
109}
110
111#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
117pub fn check() -> Result<(), Error> {
118 if !failed() {
119 return Ok(());
120 }
121
122 let error = Error {
123 short: getmsg("SHORT"),
124 explain: getmsg("EXPLAIN"),
125 long: getmsg("LONG"),
126 traceback: qcktrc(),
127 };
128 reset();
129 Err(error)
130}
131
132fn inout(value: &str) -> Vec<SpiceChar> {
134 let mut buffer = vec![0 as SpiceChar; MAX_LEN_OUT.max(value.len() + 1)];
135 for (target, byte) in buffer.iter_mut().zip(value.as_bytes()) {
136 *target = *byte as SpiceChar;
137 }
138 buffer
139}
140
141macro_rules! inout_routine {
143 ($($name:ident => $cname:ident, $doc:expr);* $(;)?) => {$(
144 #[doc = $doc]
145 #[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
149 pub fn $name(op: &str, value: &str) -> String {
150 let op = to_cstring(op);
151 let mut buffer = inout(value);
152 unsafe {
153 crate::c::$cname(
154 op.as_ptr() as *mut SpiceChar,
155 buffer.len() as SpiceInt,
156 buffer.as_mut_ptr(),
157 )
158 };
159 from_cbuf(&buffer)
160 }
161 )*};
162}
163
164inout_routine! {
165 erract => erract_c, "Retrieve or set the default error action.";
166 errdev => errdev_c, "Retrieve or set the name of the current output device for error messages.";
167 errprt => errprt_c, "Retrieve or set the list of error message items to be output.";
168}
169
170#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
176pub fn quiet() {
177 erract("SET", "RETURN");
178 errdev("SET", "NULL");
179}
180
181#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
185pub fn loud() {
186 erract("SET", "ABORT");
187 errdev("SET", "SCREEN");
188}