use crate::{
errors::IntegrityError, math::interpolation::InterpolationError, prelude::InputOutputError,
NaifId,
};
use core::fmt::Display;
use hifitime::Epoch;
use snafu::prelude::*;
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout};
pub(crate) const RCRD_LEN: usize = 1024;
#[allow(clippy::module_inception)]
pub mod daf;
pub(crate) mod data_types;
pub mod mut_daf;
pub use data_types::DataType as DafDataType;
pub mod file_record;
pub mod name_record;
pub mod summary_record;
pub mod datatypes;
pub use daf::DAF;
use crate::errors::DecodingError;
use core::fmt::Debug;
pub use file_record::FileRecord;
pub use name_record::NameRecord;
pub use summary_record::SummaryRecord;
use self::file_record::FileRecordError;
pub trait NAIFRecord:
IntoBytes + FromBytes + Sized + Default + Debug + Immutable + KnownLayout
{
const SIZE: usize = core::mem::size_of::<Self>();
}
pub trait NAIFSummaryRecord: NAIFRecord + Copy + Immutable + KnownLayout {
type Error: 'static + std::error::Error;
fn start_index(&self) -> usize;
fn data_type(&self) -> Result<DafDataType, Self::Error>;
fn end_index(&self) -> usize;
fn start_epoch(&self) -> Epoch;
fn end_epoch(&self) -> Epoch;
fn start_epoch_et_s(&self) -> f64;
fn end_epoch_et_s(&self) -> f64;
fn id(&self) -> i32;
fn is_empty(&self) -> bool {
self.start_index() == self.end_index()
}
fn update_indexes(&mut self, start: usize, end: usize);
fn update_epochs(&mut self, start_epoch: Epoch, end_epoch: Epoch);
const NAME: &'static str;
}
pub trait NAIFDataSet<'a>: Sized + Display + PartialEq {
type RecordKind: NAIFDataRecord<'a>;
type StateKind;
const DATASET_NAME: &'static str;
fn from_f64_slice(slice: &'a [f64]) -> Result<Self, DecodingError>;
fn to_f64_daf_vec(&self) -> Result<Vec<f64>, InterpolationError> {
Err(InterpolationError::UnsupportedOperation {
kind: Self::DATASET_NAME,
op: "building new DAF",
})
}
fn nth_record(&self, n: usize) -> Result<Self::RecordKind, DecodingError>;
fn evaluate<S: NAIFSummaryRecord>(
&self,
epoch: Epoch,
summary: &S,
) -> Result<Self::StateKind, InterpolationError>;
fn check_integrity(&self) -> Result<(), IntegrityError>;
fn truncate<S: NAIFSummaryRecord>(
self,
_summary: &S,
_new_start: Option<Epoch>,
_new_end: Option<Epoch>,
) -> Result<Self, InterpolationError> {
Err(InterpolationError::UnsupportedOperation {
kind: Self::DATASET_NAME,
op: "truncation",
})
}
}
pub trait NAIFDataRecord<'a>: Display {
fn from_slice_f64(slice: &'a [f64]) -> Self;
}
#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
#[non_exhaustive]
pub enum DAFError {
#[snafu(display("No DAF/{kind} data have been loaded"))]
NoDAFLoaded { kind: &'static str },
MaxRecursionDepth,
#[snafu(display("DAF/{kind}: summary {id} not present"))]
SummaryIdError { kind: &'static str, id: NaifId },
#[snafu(display(
"DAF/{kind}: summary {id} valid from {start} to {end} but not at requested {epoch}"
))]
SummaryIdAtEpochError {
kind: &'static str,
id: NaifId,
epoch: Epoch,
start: Epoch,
end: Epoch,
},
#[snafu(display("DAF/{kind}: summary `{name}` not present"))]
SummaryNameError { kind: &'static str, name: String },
#[snafu(display(
"DAF/{kind}: summary `{name}` not present or does not cover requested epoch of {epoch}"
))]
SummaryNameAtEpochError {
kind: &'static str,
name: String,
epoch: Epoch,
},
#[snafu(display("DAF/{kind}: no interpolation data for `{name}` at {epoch}"))]
InterpolationDataErrorFromName {
kind: &'static str,
name: String,
epoch: Epoch,
},
#[snafu(display("DAF/{kind}: no interpolation data for {id} at {epoch}"))]
InterpolationDataErrorFromId {
kind: &'static str,
id: NaifId,
epoch: Epoch,
},
#[snafu(display("DAF/{kind}: file record {source}"))]
FileRecord {
kind: &'static str,
#[snafu(backtrace)]
source: FileRecordError,
},
#[snafu(display(
"DAF/{kind}: summary contains no data (start and end index both set to {idx})"
))]
EmptySummary { kind: &'static str, idx: usize },
#[snafu(display("DAF/{kind}: no data record for `{name}`"))]
NameError { kind: &'static str, name: String },
#[snafu(display("DAF/{kind}: summary: {source}"))]
DecodingSummary {
kind: &'static str,
#[snafu(backtrace)]
source: DecodingError,
},
#[snafu(display("DAF/{kind}: comments: {source}"))]
DecodingComments {
kind: &'static str,
#[snafu(backtrace)]
source: DecodingError,
},
#[snafu(display("DAF/{kind}: name: {source}"))]
DecodingName {
kind: &'static str,
#[snafu(backtrace)]
source: DecodingError,
},
#[snafu(display("DAF/{kind}: data index {idx}: {source}"))]
DecodingData {
kind: &'static str,
idx: usize,
#[snafu(backtrace)]
source: DecodingError,
},
DAFIntegrity {
#[snafu(backtrace)]
source: IntegrityError,
},
#[snafu(display("while {action} encountered input/output error {source}"))]
IO {
action: String,
source: InputOutputError,
},
#[snafu(display("data type {id}: {kind} (corrupted data?)"))]
Datatype { id: i32, kind: &'static str },
#[snafu(display("{dtype:?} not supported for {kind}"))]
UnsupportedDatatype {
dtype: DafDataType,
kind: &'static str,
},
#[snafu(display("DAF/{kind}: data index {idx} is invalid"))]
InvalidIndex { kind: &'static str, idx: usize },
#[snafu(display("could not build data vector of type DAF/{kind}"))]
DataBuildError { kind: &'static str },
}
impl PartialEq for DAFError {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::NoDAFLoaded { kind: l_kind }, Self::NoDAFLoaded { kind: r_kind }) => {
l_kind == r_kind
}
(
Self::SummaryIdError {
kind: l_kind,
id: l_id,
},
Self::SummaryIdError {
kind: r_kind,
id: r_id,
},
) => l_kind == r_kind && l_id == r_id,
(
Self::SummaryIdAtEpochError {
kind: l_kind,
id: l_id,
epoch: l_epoch,
start: l_start,
end: l_end,
},
Self::SummaryIdAtEpochError {
kind: r_kind,
id: r_id,
epoch: r_epoch,
start: r_start,
end: r_end,
},
) => {
l_kind == r_kind
&& l_id == r_id
&& l_epoch == r_epoch
&& l_start == r_start
&& l_end == r_end
}
(
Self::SummaryNameError {
kind: l_kind,
name: l_name,
},
Self::SummaryNameError {
kind: r_kind,
name: r_name,
},
) => l_kind == r_kind && l_name == r_name,
(
Self::SummaryNameAtEpochError {
kind: l_kind,
name: l_name,
epoch: l_epoch,
},
Self::SummaryNameAtEpochError {
kind: r_kind,
name: r_name,
epoch: r_epoch,
},
) => l_kind == r_kind && l_name == r_name && l_epoch == r_epoch,
(
Self::InterpolationDataErrorFromName {
kind: l_kind,
name: l_name,
epoch: l_epoch,
},
Self::InterpolationDataErrorFromName {
kind: r_kind,
name: r_name,
epoch: r_epoch,
},
) => l_kind == r_kind && l_name == r_name && l_epoch == r_epoch,
(
Self::InterpolationDataErrorFromId {
kind: l_kind,
id: l_id,
epoch: l_epoch,
},
Self::InterpolationDataErrorFromId {
kind: r_kind,
id: r_id,
epoch: r_epoch,
},
) => l_kind == r_kind && l_id == r_id && l_epoch == r_epoch,
(
Self::FileRecord {
kind: l_kind,
source: l_source,
},
Self::FileRecord {
kind: r_kind,
source: r_source,
},
) => l_kind == r_kind && l_source == r_source,
(
Self::EmptySummary {
kind: l_kind,
idx: l_idx,
},
Self::EmptySummary {
kind: r_kind,
idx: r_idx,
},
) => l_kind == r_kind && l_idx == r_idx,
(
Self::NameError {
kind: l_kind,
name: l_name,
},
Self::NameError {
kind: r_kind,
name: r_name,
},
) => l_kind == r_kind && l_name == r_name,
(
Self::DecodingSummary {
kind: l_kind,
source: l_source,
},
Self::DecodingSummary {
kind: r_kind,
source: r_source,
},
) => l_kind == r_kind && l_source == r_source,
(
Self::DecodingComments {
kind: l_kind,
source: l_source,
},
Self::DecodingComments {
kind: r_kind,
source: r_source,
},
) => l_kind == r_kind && l_source == r_source,
(
Self::DecodingName {
kind: l_kind,
source: l_source,
},
Self::DecodingName {
kind: r_kind,
source: r_source,
},
) => l_kind == r_kind && l_source == r_source,
(
Self::DecodingData {
kind: l_kind,
idx: l_idx,
source: l_source,
},
Self::DecodingData {
kind: r_kind,
idx: r_idx,
source: r_source,
},
) => l_kind == r_kind && l_idx == r_idx && l_source == r_source,
(Self::DAFIntegrity { source: l_source }, Self::DAFIntegrity { source: r_source }) => {
l_source == r_source
}
(
Self::IO {
action: l_action,
source: _l_source,
},
Self::IO {
action: r_action,
source: _r_source,
},
) => l_action == r_action,
_ => core::mem::discriminant(self) == core::mem::discriminant(other),
}
}
}