use crate::c::{SpiceChar, SpiceInt};
use crate::core::ffi::{from_cbuf, to_cstring};
use crate::MAX_LEN_OUT;
use std::fmt;
#[cfg(any(feature = "lock", doc))]
use {crate::core::lock::SpiceLock, spice_derive::impl_for};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Error {
pub short: String,
pub explain: String,
pub long: String,
pub traceback: String,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.short)?;
for detail in [&self.explain, &self.long] {
if !detail.is_empty() {
write!(f, ": {detail}")?;
}
}
if !self.traceback.is_empty() {
write!(f, " [{}]", self.traceback)?;
}
Ok(())
}
}
impl std::error::Error for Error {}
#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
pub fn failed() -> bool {
unsafe { crate::c::failed_c() != 0 }
}
#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
pub fn reset() {
unsafe { crate::c::reset_c() }
}
#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
pub fn getmsg(option: &str) -> String {
let option = to_cstring(option);
let mut message = vec![0 as SpiceChar; MAX_LEN_OUT];
unsafe {
crate::c::getmsg_c(
option.as_ptr() as *mut SpiceChar,
message.len() as SpiceInt,
message.as_mut_ptr(),
)
};
from_cbuf(&message)
}
#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
pub fn qcktrc() -> String {
let mut trace = vec![0 as SpiceChar; MAX_LEN_OUT];
unsafe { crate::c::qcktrc_c(trace.len() as SpiceInt, trace.as_mut_ptr()) };
from_cbuf(&trace)
}
#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
pub fn check() -> Result<(), Error> {
if !failed() {
return Ok(());
}
let error = Error {
short: getmsg("SHORT"),
explain: getmsg("EXPLAIN"),
long: getmsg("LONG"),
traceback: qcktrc(),
};
reset();
Err(error)
}
fn inout(value: &str) -> Vec<SpiceChar> {
let mut buffer = vec![0 as SpiceChar; MAX_LEN_OUT.max(value.len() + 1)];
for (target, byte) in buffer.iter_mut().zip(value.as_bytes()) {
*target = *byte as SpiceChar;
}
buffer
}
macro_rules! inout_routine {
($($name:ident => $cname:ident, $doc:expr);* $(;)?) => {$(
#[doc = $doc]
#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
pub fn $name(op: &str, value: &str) -> String {
let op = to_cstring(op);
let mut buffer = inout(value);
unsafe {
crate::c::$cname(
op.as_ptr() as *mut SpiceChar,
buffer.len() as SpiceInt,
buffer.as_mut_ptr(),
)
};
from_cbuf(&buffer)
}
)*};
}
inout_routine! {
erract => erract_c, "Retrieve or set the default error action.";
errdev => errdev_c, "Retrieve or set the name of the current output device for error messages.";
errprt => errprt_c, "Retrieve or set the list of error message items to be output.";
}
#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
pub fn quiet() {
erract("SET", "RETURN");
errdev("SET", "NULL");
}
#[cfg_attr(any(feature = "lock", doc), impl_for(SpiceLock))]
pub fn loud() {
erract("SET", "ABORT");
errdev("SET", "SCREEN");
}