1use core::str::FromStr;
12use std::fmt::Debug;
13use std::{collections::HashMap, hash::Hash};
14
15use snafu::{whatever, Whatever};
16
17use self::parser::Assignment;
18
19pub mod fk;
20
21pub mod parser;
22pub mod tpc;
23
24pub trait KPLItem: Debug + Default {
25 type Parameter: Eq + Hash;
26 fn extract_key(data: &Assignment) -> i32;
28 fn data(&self) -> &HashMap<Self::Parameter, KPLValue>;
29 fn parse(&mut self, data: Assignment);
30}
31
32#[derive(Clone, Debug, PartialEq)]
33pub enum KPLValue {
34 Float(f64),
35 Matrix(Vec<f64>),
36 String(String),
37 Integer(i32),
38}
39
40impl KPLValue {
41 pub fn to_vec_f64(&self) -> Result<Vec<f64>, Whatever> {
42 match self {
43 KPLValue::Matrix(data) => Ok(data.clone()),
44 _ => whatever!("can only convert matrices to vec of f64 but this is {self:?}"),
45 }
46 }
47
48 pub fn to_i32(&self) -> Result<i32, Whatever> {
49 match self {
50 KPLValue::Integer(data) => Ok(*data),
51 _ => whatever!("can only convert Integer to i32 but this is {self:?}"),
52 }
53 }
54
55 pub fn to_string(&self) -> Result<String, Whatever> {
56 match self {
57 KPLValue::String(data) => Ok(data.clone()),
58 _ => whatever!("can only convert Integer to i32 but this is {self:?}"),
59 }
60 }
61}
62
63impl From<f64> for KPLValue {
64 fn from(value: f64) -> Self {
65 Self::Float(value)
66 }
67}
68
69impl From<i32> for KPLValue {
70 fn from(value: i32) -> Self {
71 Self::Integer(value)
72 }
73}
74
75impl From<String> for KPLValue {
76 fn from(value: String) -> Self {
77 Self::String(value)
78 }
79}
80
81impl TryFrom<&KPLValue> for f64 {
82 type Error = Whatever;
83
84 fn try_from(value: &KPLValue) -> Result<Self, Self::Error> {
85 match value {
86 KPLValue::Float(data) => Ok(*data),
87 _ => whatever!("can only convert float to f64 but this is {value:?}"),
88 }
89 }
90}
91
92#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
94pub enum Parameter {
95 NutPrecRa,
96 NutPrecDec,
97 NutPrecPm,
98 NutPrecAngles,
99 MaxPhaseDegree,
100 LongAxis,
101 PoleRa,
102 PoleDec,
103 Radii,
104 PrimeMeridian,
105 GeoMagNorthPoleCenterDipoleLatitude,
106 GeoMagNorthPoleCenterDipoleLongitude,
107 GravitationalParameter,
108 Class,
109 Center,
110 ClassId,
111 Angles,
112 Relative,
113 Matrix,
114 Units,
115 Axes,
116}
117
118impl FromStr for Parameter {
119 type Err = Whatever;
120
121 fn from_str(s: &str) -> Result<Self, Self::Err> {
122 match s {
123 "NUT_PREC_RA" => Ok(Self::NutPrecRa),
124 "NUT_PREC_DEC" => Ok(Self::NutPrecDec),
125 "NUT_PREC_PM" => Ok(Self::NutPrecPm),
126 "LONG_AXIS" => Ok(Self::LongAxis),
127 "POLE_DEC" => Ok(Self::PoleDec),
128 "POLE_RA" => Ok(Self::PoleRa),
129 "RADII" => Ok(Self::Radii),
130 "PM" => Ok(Self::PrimeMeridian),
131 "NUT_PREC_ANGLES" => Ok(Self::NutPrecAngles),
132 "N_GEOMAG_CTR_DIPOLE_LAT" => Ok(Self::GeoMagNorthPoleCenterDipoleLatitude),
133 "N_GEOMAG_CTR_DIPOLE_LON" => Ok(Self::GeoMagNorthPoleCenterDipoleLongitude),
134 "GM" => Ok(Self::GravitationalParameter),
135 "CLASS" => Ok(Self::Class),
136 "CLASS_ID" => Ok(Self::ClassId),
137 "CENTER" => Ok(Self::Center),
138 "ANGLES" => Ok(Self::Angles),
139 "RELATIVE" => Ok(Self::Relative),
140 "MATRIX" => Ok(Self::Matrix),
141 "UNITS" => Ok(Self::Units),
142 "AXES" => Ok(Self::Axes),
143 "MAX_PHASE_DEGREE" => Ok(Self::MaxPhaseDegree),
144 "GMLIST" | "NAME" | "SPEC" => {
145 whatever!("unsupported parameter `{s}`")
146 }
147 _ => {
148 whatever!("unknown parameter `{s}`")
149 }
150 }
151 }
152}