1use crate::error::{CcsdsNdmError, Result};
6use crate::traits::{FromKvnFloat, FromKvnValue};
7use fast_float;
8use serde::{Deserialize, Serialize};
9use std::str::FromStr;
10use thiserror::Error;
11use winnow::ascii::{digit0, digit1};
12use winnow::combinator::{alt, eof, opt, seq, terminated};
13use winnow::token::one_of;
14use winnow::Parser;
15
16#[derive(Debug, PartialEq, Eq, Clone, Copy)]
24pub struct Epoch {
25 bytes: [u8; 64],
26 len: u8,
27}
28
29impl Serialize for Epoch {
30 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
31 where
32 S: serde::Serializer,
33 {
34 serializer.serialize_str(self.as_str())
35 }
36}
37
38impl<'de> Deserialize<'de> for Epoch {
39 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
40 where
41 D: serde::Deserializer<'de>,
42 {
43 let s = String::deserialize(deserializer)?;
44 Epoch::try_from(s).map_err(serde::de::Error::custom)
45 }
46}
47
48#[derive(Error, Debug, PartialEq, Clone)]
49pub enum EpochError {
50 #[error("invalid epoch format: '{0}'")]
51 InvalidFormat(String),
52}
53
54fn is_valid_epoch(s: &str) -> bool {
55 fn parser(input: &mut &str) -> winnow::Result<()> {
56 alt((
57 seq!(
59 opt('-'),
60 digit1.verify(|s: &str| s.len() >= 4),
61 '-',
62 alt((
63 seq!(
64 digit1.verify(|s: &str| s.len() == 2),
65 '-',
66 digit1.verify(|s: &str| s.len() == 2)
67 )
68 .void(),
69 seq!(digit1.verify(|s: &str| s.len() == 3)).void(),
70 )),
71 'T',
72 digit1.verify(|s: &str| s.len() == 2),
73 ':',
74 digit1.verify(|s: &str| s.len() == 2),
75 ':',
76 digit1.verify(|s: &str| s.len() == 2),
77 opt(seq!('.', digit0).void()),
78 opt(alt((
79 "Z".void(),
80 seq!(
81 one_of(['+', '-']),
82 digit1.verify(|s: &str| s.len() == 2),
83 ':',
84 digit1.verify(|s: &str| s.len() == 2)
85 )
86 .void()
87 )))
88 )
89 .void(),
90 seq!(
92 opt(one_of(['+', '-'])),
93 digit0,
94 opt(seq!('.', digit0).void())
95 )
96 .void(),
97 ))
98 .parse_next(input)
99 }
100
101 terminated(parser, eof).parse(s).is_ok()
102}
103
104impl Epoch {
105 pub fn new(value: &str) -> std::result::Result<Self, EpochError> {
106 if value.len() > 64 {
109 return Err(EpochError::InvalidFormat(value.to_string()));
110 }
111
112 if value.is_empty() || is_valid_epoch(value) {
113 let mut bytes = [0u8; 64];
114 bytes[..value.len()].copy_from_slice(value.as_bytes());
115 Ok(Epoch {
116 bytes,
117 len: value.len() as u8,
118 })
119 } else {
120 Err(EpochError::InvalidFormat(value.to_string()))
121 }
122 }
123 pub fn as_str(&self) -> &str {
124 std::str::from_utf8(&self.bytes[..self.len as usize])
126 .expect("Epoch bytes must be valid UTF-8")
127 }
128
129 pub fn is_empty(&self) -> bool {
131 self.len == 0
132 }
133}
134
135impl std::fmt::Display for Epoch {
136 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
137 write!(f, "{}", self.as_str())
138 }
139}
140
141impl FromStr for Epoch {
142 type Err = EpochError;
143 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
144 Self::new(s)
145 }
146}
147
148impl TryFrom<String> for Epoch {
149 type Error = EpochError;
150 fn try_from(value: String) -> std::result::Result<Self, Self::Error> {
151 Self::new(&value)
152 }
153}
154
155pub trait FromKvn: Sized {
164 fn from_kvn(value: &str, unit: Option<&str>) -> Result<Self>;
173}
174
175#[derive(Serialize, Debug, PartialEq, Clone, Default)]
185pub struct UnitValue<V, U> {
186 #[serde(rename = "$value")]
187 pub value: V,
188 #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
189 pub units: Option<U>,
190}
191
192impl<V, U> FromStr for UnitValue<V, U>
193where
194 UnitValue<V, U>: FromKvn,
195{
196 type Err = crate::error::CcsdsNdmError;
197
198 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
199 Self::from_kvn(s, None)
200 }
201}
202
203impl<'de, V, U> serde::Deserialize<'de> for UnitValue<V, U>
204where
205 V: serde::Deserialize<'de> + std::str::FromStr,
206 V::Err: std::fmt::Display,
207 U: serde::Deserialize<'de>,
208{
209 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
210 where
211 D: serde::Deserializer<'de>,
212 {
213 struct UnitValueVisitor<V, U>(std::marker::PhantomData<(V, U)>);
214
215 impl<'de, V, U> serde::de::Visitor<'de> for UnitValueVisitor<V, U>
216 where
217 V: serde::Deserialize<'de> + std::str::FromStr,
218 V::Err: std::fmt::Display,
219 U: serde::Deserialize<'de>,
220 {
221 type Value = UnitValue<V, U>;
222
223 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
224 formatter.write_str("a primitive value or a map with $value and optionally @units")
225 }
226
227 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
228 where
229 E: serde::de::Error,
230 {
231 let value = v.parse::<V>().map_err(E::custom)?;
232 Ok(UnitValue { value, units: None })
233 }
234
235 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
236 where
237 A: serde::de::MapAccess<'de>,
238 {
239 let mut value = None;
240 let mut units = None;
241
242 while let Some(key) = map.next_key::<String>()? {
243 if key == "$value" || key == "$text" {
244 if value.is_some() {
245 return Err(serde::de::Error::duplicate_field("$value"));
246 }
247 value = Some(map.next_value()?);
248 } else if key == "@units" {
249 if units.is_some() {
250 return Err(serde::de::Error::duplicate_field("@units"));
251 }
252 units = Some(map.next_value()?);
253 } else {
254 let _: serde::de::IgnoredAny = map.next_value()?;
255 }
256 }
257
258 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
259 Ok(UnitValue { value, units })
260 }
261 }
262
263 deserializer.deserialize_any(UnitValueVisitor(std::marker::PhantomData))
264 }
265}
266
267impl<V: std::fmt::Display, U> std::fmt::Display for UnitValue<V, U> {
268 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269 write!(f, "{}", self.value)
270 }
271}
272
273impl<V, U> UnitValue<V, U> {
274 pub fn new(value: V, units: Option<U>) -> Self {
276 Self { value, units }
277 }
278}
279
280impl<V, U> FromKvn for UnitValue<V, U>
281where
282 V: FromStr,
283 CcsdsNdmError: From<V::Err>,
284 U: FromStr,
285 CcsdsNdmError: From<U::Err>,
286{
287 fn from_kvn(value: &str, unit: Option<&str>) -> Result<Self> {
292 let value = value.parse::<V>()?;
293
294 let units = match unit {
295 Some(u_str) => Some(u_str.parse::<U>().map_err(CcsdsNdmError::from)?),
296 None => None,
297 };
298
299 Ok(UnitValue { value, units })
300 }
301}
302
303impl<U> FromKvnFloat for UnitValue<f64, U>
304where
305 U: FromStr,
306 CcsdsNdmError: From<U::Err>,
307{
308 fn from_kvn_float(value: f64, unit: Option<&str>) -> Result<Self> {
309 let units = match unit {
310 Some(u_str) => Some(u_str.parse::<U>().map_err(CcsdsNdmError::from)?),
311 None => None,
312 };
313 Ok(UnitValue { value, units })
314 }
315}
316
317macro_rules! define_unit_type {
329 ($type_alias:ident, $unit_enum:ident, $default_variant:ident, { $($variant:ident => $str_rep:expr),+ $(,)? }) => {
330 #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
331 pub enum $unit_enum {
332 $(#[serde(rename = $str_rep)] $variant),+
333 }
334
335 impl Default for $unit_enum {
336 fn default() -> Self { Self::$default_variant }
337 }
338
339 impl std::fmt::Display for $unit_enum {
340 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
341 match self {
342 $(Self::$variant => write!(f, $str_rep)),+
343 }
344 }
345 }
346
347 impl std::str::FromStr for $unit_enum {
348 type Err = crate::error::EnumParseError;
349 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
350 match s {
351 $($str_rep => Ok(Self::$variant)),+,
352 _ => Err(crate::error::EnumParseError {
353 field: "unit",
354 value: s.to_string(),
355 expected: stringify!($($str_rep),+),
356 })
357 }
358 }
359 }
360
361 pub type $type_alias = UnitValue<f64, $unit_enum>;
362 };
363}
364
365macro_rules! define_required_type {
371 ($name:ident, $unit_enum:ident, $default_unit:ident) => {
372 #[derive(Serialize, Debug, PartialEq, Clone, Default)]
373 pub struct $name {
374 #[serde(rename = "$value")]
375 pub value: f64,
376 #[serde(rename = "@units")]
377 pub units: $unit_enum,
378 }
379
380 impl<'de> serde::Deserialize<'de> for $name {
381 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
382 where
383 D: serde::Deserializer<'de>,
384 {
385 struct Visitor;
386 impl<'de> serde::de::Visitor<'de> for Visitor {
387 type Value = $name;
388 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
389 formatter.write_str("a float value or map with $value and @units")
390 }
391
392 fn visit_f64<E>(self, v: f64) -> std::result::Result<Self::Value, E>
393 where
394 E: serde::de::Error,
395 {
396 Ok($name::new(v))
397 }
398
399 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
400 where
401 E: serde::de::Error,
402 {
403 let val = v.parse::<f64>().map_err(E::custom)?;
404 Ok($name::new(val))
405 }
406
407 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
408 where
409 A: serde::de::MapAccess<'de>,
410 {
411 let mut value = None;
412 let mut units = None;
413 while let Some(key) = map.next_key::<String>()? {
414 if key == "$value" || key == "$text" {
415 value = Some(map.next_value::<f64>()?);
416 } else if key == "@units" {
417 units = Some(map.next_value::<$unit_enum>()?);
418 } else {
419 let _ = map.next_value::<serde::de::IgnoredAny>()?;
420 }
421 }
422 let value =
423 value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
424 let mut s = $name::new(value);
425 if let Some(u) = units {
426 s.units = u;
427 }
428 Ok(s)
429 }
430 }
431 deserializer.deserialize_any(Visitor)
432 }
433 }
434 impl $name {
435 pub fn new(value: f64) -> Self {
436 Self {
437 value,
438 units: $unit_enum::$default_unit,
439 }
440 }
441 pub fn to_unit_value(&self) -> UnitValue<f64, $unit_enum> {
442 UnitValue {
443 value: self.value,
444 units: Some(self.units.clone()),
445 }
446 }
447 }
448 impl std::fmt::Display for $name {
449 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
450 write!(f, "{}", self.value)
451 }
452 }
453 impl FromKvnFloat for $name {
454 fn from_kvn_float(value: f64, _unit: Option<&str>) -> Result<Self> {
455 Ok(Self::new(value))
456 }
457 }
458 };
459}
460
461macro_rules! define_unit_enum {
463 ($unit_enum:ident, $default_variant:ident, { $($variant:ident => $str_rep:expr),+ $(,)? }) => {
464 #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
465 pub enum $unit_enum { $(#[serde(rename = $str_rep)] $variant),+ }
466 impl Default for $unit_enum { fn default() -> Self { Self::$default_variant } }
467 impl std::fmt::Display for $unit_enum {
468 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
469 match self { $(Self::$variant => write!(f, $str_rep)),+ }
470 }
471 }
472 impl std::str::FromStr for $unit_enum {
473 type Err = crate::error::EnumParseError;
474 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
475 match s { $($str_rep => Ok(Self::$variant)),+, _ => Err(crate::error::EnumParseError {
476 field: "unit",
477 value: s.to_string(),
478 expected: stringify!($($str_rep),+),
479 }) }
480 }
481 }
482 };
483}
484
485macro_rules! define_required_unit_type {
487 ($name:ident, $unit_enum:ident, $default_variant:ident, { $($variant:ident => $str_rep:expr),+ $(,)? }) => {
488 define_unit_enum!($unit_enum, $default_variant, { $($variant => $str_rep),+ });
489 define_required_type!($name, $unit_enum, $default_variant);
490 };
491}
492
493define_unit_type!(
499 Acc,
500 AccUnits,
501 KmPerS2,
502 { KmPerS2 => "km/s**2" }
503);
504
505define_unit_type!(
507 Position,
508 PositionUnits,
509 Km,
510 { Km => "km" }
511);
512
513define_required_type!(PositionRequired, PositionUnits, Km);
514define_unit_type!(
517 Velocity,
518 VelocityUnits,
519 KmPerS,
520 { KmPerS => "km/s" }
521);
522
523define_required_type!(VelocityRequired, VelocityUnits, KmPerS);
524pub type Distance = Position;
526
527define_unit_enum!(AngleUnits, Deg, { Deg => "deg" });
530
531#[derive(Serialize, Debug, PartialEq, Clone)]
532pub struct Angle {
533 #[serde(rename = "$value")]
534 pub value: f64,
535 #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
536 pub units: Option<AngleUnits>,
537}
538
539impl std::str::FromStr for Angle {
540 type Err = crate::error::CcsdsNdmError;
541 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
542 let val = s.parse::<f64>()?;
543 Self::new(val, None)
544 }
545}
546
547impl<'de> serde::Deserialize<'de> for Angle {
548 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
549 where
550 D: serde::Deserializer<'de>,
551 {
552 struct AngleVisitor;
553
554 impl<'de> serde::de::Visitor<'de> for AngleVisitor {
555 type Value = Angle;
556
557 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
558 formatter.write_str("a primitive value or a map with $value and optionally @units")
559 }
560
561 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
562 where
563 E: serde::de::Error,
564 {
565 v.parse::<Angle>().map_err(E::custom)
566 }
567
568 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
569 where
570 A: serde::de::MapAccess<'de>,
571 {
572 let mut value = None;
573 let mut units = None;
574
575 while let Some(key) = map.next_key::<String>()? {
576 if key == "$value" || key == "$text" {
577 value = Some(map.next_value()?);
578 } else if key == "@units" {
579 units = Some(map.next_value()?);
580 } else {
581 let _: serde::de::IgnoredAny = map.next_value()?;
582 }
583 }
584
585 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
586 Angle::new(value, units).map_err(serde::de::Error::custom)
587 }
588 }
589
590 deserializer.deserialize_any(AngleVisitor)
591 }
592}
593
594impl Angle {
595 pub fn new(value: f64, units: Option<AngleUnits>) -> Result<Self> {
597 if !(-360.0..360.0).contains(&value) {
598 return Err(crate::error::ValidationError::OutOfRange {
599 name: "Angle".into(),
600 value: value.to_string(),
601 expected: "[-360, 360)".into(),
602 line: None,
603 }
604 .into());
605 }
606 Ok(Self { value, units })
607 }
608 pub fn to_unit_value(&self) -> UnitValue<f64, AngleUnits> {
609 UnitValue {
610 value: self.value,
611 units: self.units.clone(),
612 }
613 }
614}
615impl FromKvnFloat for Angle {
616 fn from_kvn_float(value: f64, unit: Option<&str>) -> Result<Self> {
617 let uv = UnitValue::<f64, AngleUnits>::from_kvn_float(value, unit)?;
618 Self::new(uv.value, uv.units)
619 }
620}
621define_unit_enum!(AngleRateUnits, DegPerS, { DegPerS => "deg/s" });
624
625pub type AngleRate = UnitValue<f64, AngleRateUnits>;
626
627define_unit_type!(AngMomentum, AngMomentumUnits, NmS, { NmS => "N*m*s" });
629
630define_unit_enum!(DayIntervalUnits, D, { D => "d" });
633
634#[derive(Serialize, Debug, PartialEq, Clone)]
635pub struct DayInterval {
636 #[serde(rename = "$value")]
637 pub value: f64,
638 #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
639 pub units: Option<DayIntervalUnits>,
640}
641
642impl std::str::FromStr for DayInterval {
643 type Err = crate::error::CcsdsNdmError;
644 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
645 let val = s.parse::<f64>()?;
646 Self::new(val, None)
647 }
648}
649
650impl<'de> serde::Deserialize<'de> for DayInterval {
651 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
652 where
653 D: serde::Deserializer<'de>,
654 {
655 struct DayIntervalVisitor;
656
657 impl<'de> serde::de::Visitor<'de> for DayIntervalVisitor {
658 type Value = DayInterval;
659
660 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
661 formatter.write_str("a primitive value or a map with $value and optionally @units")
662 }
663
664 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
665 where
666 E: serde::de::Error,
667 {
668 v.parse::<DayInterval>().map_err(E::custom)
669 }
670
671 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
672 where
673 A: serde::de::MapAccess<'de>,
674 {
675 let mut value = None;
676 let mut units = None;
677
678 while let Some(key) = map.next_key::<String>()? {
679 if key == "$value" || key == "$text" {
680 value = Some(map.next_value::<f64>()?);
681 } else if key == "@units" {
682 units = Some(map.next_value::<DayIntervalUnits>()?);
683 } else {
684 let _: serde::de::IgnoredAny = map.next_value()?;
685 }
686 }
687
688 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
689 DayInterval::new(value, units).map_err(serde::de::Error::custom)
690 }
691 }
692
693 deserializer.deserialize_any(DayIntervalVisitor)
694 }
695}
696
697impl DayInterval {
698 pub fn new(value: f64, units: Option<DayIntervalUnits>) -> Result<Self> {
700 if value < 0.0 {
701 return Err(crate::error::ValidationError::OutOfRange {
702 name: "DayInterval".into(),
703 value: value.to_string(),
704 expected: ">= 0".into(),
705 line: None,
706 }
707 .into());
708 }
709 Ok(Self { value, units })
710 }
711 pub fn to_unit_value(&self) -> UnitValue<f64, DayIntervalUnits> {
712 UnitValue {
713 value: self.value,
714 units: self.units.clone(),
715 }
716 }
717}
718impl FromKvnFloat for DayInterval {
719 fn from_kvn_float(value: f64, unit: Option<&str>) -> Result<Self> {
720 let uv = UnitValue::<f64, DayIntervalUnits>::from_kvn_float(value, unit)?;
721 Self::new(uv.value, uv.units)
722 }
723}
724impl std::fmt::Display for DayInterval {
725 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
726 write!(f, "{}", self.value)
727 }
728}
729#[derive(Serialize, Debug, PartialEq, Clone)]
730pub struct Percentage {
731 #[serde(rename = "$value")]
732 pub value: f64,
733 #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
734 pub units: Option<PercentageUnits>,
735}
736
737impl<'de> serde::Deserialize<'de> for Percentage {
738 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
739 where
740 D: serde::Deserializer<'de>,
741 {
742 struct Visitor;
743 impl<'de> serde::de::Visitor<'de> for Visitor {
744 type Value = Percentage;
745 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
746 formatter.write_str("a float value or map with $value and optionally @units")
747 }
748
749 fn visit_f64<E>(self, v: f64) -> std::result::Result<Self::Value, E>
750 where
751 E: serde::de::Error,
752 {
753 Percentage::new(v, None).map_err(E::custom)
754 }
755
756 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
757 where
758 E: serde::de::Error,
759 {
760 let val = v.parse::<f64>().map_err(E::custom)?;
761 Percentage::new(val, None).map_err(E::custom)
762 }
763
764 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
765 where
766 A: serde::de::MapAccess<'de>,
767 {
768 let mut value = None;
769 let mut units = None;
770 while let Some(key) = map.next_key::<String>()? {
771 if key == "$value" || key == "$text" {
772 value = Some(map.next_value::<f64>()?);
773 } else if key == "@units" {
774 units = Some(map.next_value::<PercentageUnits>()?);
775 } else {
776 let _ = map.next_value::<serde::de::IgnoredAny>()?;
777 }
778 }
779 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
780 Percentage::new(value, units).map_err(serde::de::Error::custom)
781 }
782 }
783 deserializer.deserialize_any(Visitor)
784 }
785}
786
787impl Percentage {
788 pub fn new(value: f64, units: Option<PercentageUnits>) -> Result<Self> {
789 if !(0.0..=100.0).contains(&value) {
790 return Err(crate::error::ValidationError::OutOfRange {
791 name: "Percentage".into(),
792 value: value.to_string(),
793 expected: "[0, 100]".into(),
794 line: None,
795 }
796 .into());
797 }
798 Ok(Self { value, units })
799 }
800 pub fn to_unit_value(&self) -> UnitValue<f64, PercentageUnits> {
801 UnitValue {
802 value: self.value,
803 units: self.units.clone(),
804 }
805 }
806}
807impl FromKvnFloat for Percentage {
808 fn from_kvn_float(value: f64, unit: Option<&str>) -> Result<Self> {
809 let uv = UnitValue::<f64, PercentageUnits>::from_kvn_float(value, unit)?;
810 Self::new(uv.value, uv.units)
811 }
812}
813impl std::fmt::Display for Percentage {
814 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
815 write!(f, "{}", self.value)
816 }
817}
818#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
819pub struct DayIntervalRequired {
820 #[serde(rename = "$value")]
821 pub value: f64,
822 #[serde(rename = "@units")]
823 pub units: DayIntervalUnits,
824}
825impl DayIntervalRequired {
826 pub fn new(value: f64) -> Result<Self> {
828 if value <= 0.0 {
829 return Err(crate::error::ValidationError::OutOfRange {
830 name: "DayIntervalRequired".into(),
831 value: value.to_string(),
832 expected: "> 0".into(),
833 line: None,
834 }
835 .into());
836 }
837 Ok(Self {
838 value,
839 units: DayIntervalUnits::D,
840 })
841 }
842 pub fn to_unit_value(&self) -> UnitValue<f64, DayIntervalUnits> {
843 UnitValue {
844 value: self.value,
845 units: Some(self.units.clone()),
846 }
847 }
848}
849impl FromKvnFloat for DayIntervalRequired {
850 fn from_kvn_float(value: f64, _unit: Option<&str>) -> Result<Self> {
851 Self::new(value)
852 }
853}
854impl std::fmt::Display for DayIntervalRequired {
855 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
856 write!(f, "{}", self.value)
857 }
858}
859define_unit_enum!(FrequencyUnits, Hz, { Hz => "Hz" });
862
863#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
864pub struct Frequency {
865 #[serde(rename = "$value")]
866 pub value: f64,
867 #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
868 pub units: Option<FrequencyUnits>,
869}
870impl Frequency {
871 pub fn new(value: f64, units: Option<FrequencyUnits>) -> Result<Self> {
873 if value <= 0.0 {
874 return Err(crate::error::ValidationError::OutOfRange {
875 name: "Frequency".into(),
876 value: value.to_string(),
877 expected: "> 0".into(),
878 line: None,
879 }
880 .into());
881 }
882 Ok(Self { value, units })
883 }
884 pub fn to_unit_value(&self) -> UnitValue<f64, FrequencyUnits> {
885 UnitValue {
886 value: self.value,
887 units: self.units.clone(),
888 }
889 }
890}
891impl FromKvnFloat for Frequency {
892 fn from_kvn_float(value: f64, unit: Option<&str>) -> Result<Self> {
893 let uv = UnitValue::<f64, FrequencyUnits>::from_kvn_float(value, unit)?;
894 Self::new(uv.value, uv.units)
895 }
896}
897define_unit_type!(PositionCovariance, PositionCovarianceUnits, Km2, { Km2 => "km**2" });
900
901define_unit_type!(VelocityCovariance, VelocityCovarianceUnits, Km2PerS2, { Km2PerS2 => "km**2/s**2" });
902
903define_unit_type!(PositionVelocityCovariance, PositionVelocityCovarianceUnits, Km2PerS, { Km2PerS => "km**2/s" });
904
905define_unit_enum!(GmUnits, Km3PerS2, { Km3PerS2 => "km**3/s**2", KM3PerS2 => "KM**3/S**2" });
908
909#[derive(Serialize, Debug, PartialEq, Clone)]
910pub struct Gm {
911 #[serde(rename = "$value")]
912 pub value: f64,
913 #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
914 pub units: Option<GmUnits>,
915}
916
917impl std::str::FromStr for Gm {
918 type Err = crate::error::CcsdsNdmError;
919 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
920 let val = s.parse::<f64>()?;
921 Self::new(val, None)
922 }
923}
924
925impl<'de> serde::Deserialize<'de> for Gm {
926 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
927 where
928 D: serde::Deserializer<'de>,
929 {
930 struct GmVisitor;
931
932 impl<'de> serde::de::Visitor<'de> for GmVisitor {
933 type Value = Gm;
934
935 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
936 formatter.write_str("a primitive value or a map with $value and optionally @units")
937 }
938
939 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
940 where
941 E: serde::de::Error,
942 {
943 v.parse::<Gm>().map_err(E::custom)
944 }
945
946 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
947 where
948 A: serde::de::MapAccess<'de>,
949 {
950 let mut value = None;
951 let mut units = None;
952
953 while let Some(key) = map.next_key::<String>()? {
954 if key == "$value" || key == "$text" {
955 value = Some(map.next_value::<f64>()?);
956 } else if key == "@units" {
957 units = Some(map.next_value::<GmUnits>()?);
958 } else {
959 let _: serde::de::IgnoredAny = map.next_value()?;
960 }
961 }
962
963 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
964 Gm::new(value, units).map_err(serde::de::Error::custom)
965 }
966 }
967
968 deserializer.deserialize_any(GmVisitor)
969 }
970}
971
972impl Gm {
973 pub fn new(value: f64, units: Option<GmUnits>) -> Result<Self> {
975 if value <= 0.0 {
976 return Err(crate::error::ValidationError::OutOfRange {
977 name: "GM".into(),
978 value: value.to_string(),
979 expected: "> 0".into(),
980 line: None,
981 }
982 .into());
983 }
984 Ok(Self { value, units })
985 }
986 pub fn to_unit_value(&self) -> UnitValue<f64, GmUnits> {
987 UnitValue {
988 value: self.value,
989 units: self.units.clone(),
990 }
991 }
992}
993impl FromKvnFloat for Gm {
994 fn from_kvn_float(value: f64, unit: Option<&str>) -> Result<Self> {
995 let uv = UnitValue::<f64, GmUnits>::from_kvn_float(value, unit)?;
996 Self::new(uv.value, uv.units)
997 }
998}
999
1000define_unit_type!(
1003 Length,
1004 LengthUnits,
1005 M,
1006 { M => "m" }
1007);
1008
1009#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
1010pub struct AltitudeRequired {
1011 #[serde(rename = "$value")]
1012 pub value: f64,
1013 #[serde(rename = "@units")]
1014 pub units: LengthUnits,
1015}
1016impl AltitudeRequired {
1017 pub fn new(value: f64) -> Result<Self> {
1019 if !(-430.5..=8848.0).contains(&value) {
1020 return Err(crate::error::ValidationError::OutOfRange {
1021 name: "Altitude".into(),
1022 value: value.to_string(),
1023 expected: "[-430.5, 8848]".into(),
1024 line: None,
1025 }
1026 .into());
1027 }
1028 Ok(Self {
1029 value,
1030 units: LengthUnits::M,
1031 })
1032 }
1033 pub fn to_unit_value(&self) -> UnitValue<f64, LengthUnits> {
1034 UnitValue {
1035 value: self.value,
1036 units: Some(self.units.clone()),
1037 }
1038 }
1039}
1040impl FromKvnFloat for AltitudeRequired {
1041 fn from_kvn_float(value: f64, _unit: Option<&str>) -> Result<Self> {
1042 Self::new(value)
1043 }
1044}
1045impl std::fmt::Display for AltitudeRequired {
1046 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1047 write!(f, "{}", self.value)
1048 }
1049}
1050
1051define_required_unit_type!(Wkg, WkgUnits, WPerKg, { WPerKg => "W/kg" });
1054
1055define_unit_enum!(MassUnits, Kg, { Kg => "kg" });
1058
1059#[derive(Serialize, Debug, PartialEq, Clone)]
1060pub struct Mass {
1061 #[serde(rename = "$value")]
1062 pub value: f64,
1063 #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
1064 pub units: Option<MassUnits>,
1065}
1066
1067impl std::str::FromStr for Mass {
1068 type Err = crate::error::CcsdsNdmError;
1069 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1070 let val = s.parse::<f64>()?;
1071 Self::new(val, None)
1072 }
1073}
1074
1075impl<'de> serde::Deserialize<'de> for Mass {
1076 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
1077 where
1078 D: serde::Deserializer<'de>,
1079 {
1080 struct MassVisitor;
1081
1082 impl<'de> serde::de::Visitor<'de> for MassVisitor {
1083 type Value = Mass;
1084
1085 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1086 formatter.write_str("a primitive value or a map with $value and optionally @units")
1087 }
1088
1089 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
1090 where
1091 E: serde::de::Error,
1092 {
1093 v.parse::<Mass>().map_err(E::custom)
1094 }
1095
1096 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
1097 where
1098 A: serde::de::MapAccess<'de>,
1099 {
1100 let mut value = None;
1101 let mut units = None;
1102
1103 while let Some(key) = map.next_key::<String>()? {
1104 if key == "$value" || key == "$text" {
1105 value = Some(map.next_value()?);
1106 } else if key == "@units" {
1107 units = Some(map.next_value()?);
1108 } else {
1109 let _: serde::de::IgnoredAny = map.next_value()?;
1110 }
1111 }
1112
1113 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
1114 Mass::new(value, units).map_err(serde::de::Error::custom)
1115 }
1116 }
1117
1118 deserializer.deserialize_any(MassVisitor)
1119 }
1120}
1121
1122impl Mass {
1123 pub fn new(value: f64, units: Option<MassUnits>) -> Result<Self> {
1125 if value < 0.0 {
1126 return Err(crate::error::ValidationError::OutOfRange {
1127 name: "Mass".into(),
1128 value: value.to_string(),
1129 expected: ">= 0".into(),
1130 line: None,
1131 }
1132 .into());
1133 }
1134 Ok(Self { value, units })
1135 }
1136 pub fn to_unit_value(&self) -> UnitValue<f64, MassUnits> {
1137 UnitValue {
1138 value: self.value,
1139 units: self.units.clone(),
1140 }
1141 }
1142}
1143
1144impl FromKvnFloat for Mass {
1145 fn from_kvn_float(value: f64, unit: Option<&str>) -> Result<Self> {
1146 let uv = UnitValue::<f64, MassUnits>::from_kvn_float(value, unit)?;
1147 Self::new(uv.value, uv.units)
1148 }
1149}
1150impl std::fmt::Display for Mass {
1151 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1152 write!(f, "{}", self.value)
1153 }
1154}
1155
1156define_unit_enum!(AreaUnits, M2, { M2 => "m**2" });
1157
1158#[derive(Serialize, Debug, PartialEq, Clone)]
1159pub struct Area {
1160 #[serde(rename = "$value")]
1161 pub value: f64,
1162 #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
1163 pub units: Option<AreaUnits>,
1164}
1165
1166impl std::str::FromStr for Area {
1167 type Err = crate::error::CcsdsNdmError;
1168 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1169 let val = s.parse::<f64>()?;
1170 Self::new(val, None)
1171 }
1172}
1173
1174impl<'de> serde::Deserialize<'de> for Area {
1175 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
1176 where
1177 D: serde::Deserializer<'de>,
1178 {
1179 struct AreaVisitor;
1180
1181 impl<'de> serde::de::Visitor<'de> for AreaVisitor {
1182 type Value = Area;
1183
1184 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1185 formatter.write_str("a primitive value or a map with $value and optionally @units")
1186 }
1187
1188 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
1189 where
1190 E: serde::de::Error,
1191 {
1192 v.parse::<Area>().map_err(E::custom)
1193 }
1194
1195 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
1196 where
1197 A: serde::de::MapAccess<'de>,
1198 {
1199 let mut value = None;
1200 let mut units = None;
1201
1202 while let Some(key) = map.next_key::<String>()? {
1203 if key == "$value" || key == "$text" {
1204 value = Some(map.next_value()?);
1205 } else if key == "@units" {
1206 units = Some(map.next_value()?);
1207 } else {
1208 let _: serde::de::IgnoredAny = map.next_value()?;
1209 }
1210 }
1211
1212 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
1213 Area::new(value, units).map_err(serde::de::Error::custom)
1214 }
1215 }
1216
1217 deserializer.deserialize_any(AreaVisitor)
1218 }
1219}
1220
1221impl Area {
1222 pub fn new(value: f64, units: Option<AreaUnits>) -> Result<Self> {
1224 if value < 0.0 {
1225 return Err(crate::error::ValidationError::OutOfRange {
1226 name: "Area".into(),
1227 value: value.to_string(),
1228 expected: ">= 0".into(),
1229 line: None,
1230 }
1231 .into());
1232 }
1233 Ok(Self { value, units })
1234 }
1235 pub fn to_unit_value(&self) -> UnitValue<f64, AreaUnits> {
1236 UnitValue {
1237 value: self.value,
1238 units: self.units.clone(),
1239 }
1240 }
1241}
1242impl FromKvnFloat for Area {
1243 fn from_kvn_float(value: f64, unit: Option<&str>) -> Result<Self> {
1244 let uv = UnitValue::<f64, AreaUnits>::from_kvn_float(value, unit)?;
1245 Self::new(uv.value, uv.units)
1246 }
1247}
1248impl std::fmt::Display for Area {
1249 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1250 write!(f, "{}", self.value)
1251 }
1252}
1253define_required_unit_type!(Ms2, Ms2Units, MPerS2, { MPerS2 => "m/s**2" });
1254
1255impl std::str::FromStr for Ms2 {
1256 type Err = std::num::ParseFloatError;
1257 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1258 let v: f64 = s.parse()?;
1259 Ok(Self::new(v))
1260 }
1261}
1262
1263define_unit_type!(Km2, Km2Units, Km2, { Km2 => "km**2" });
1264
1265define_unit_type!(Km2s, Km2sUnits, Km2PerS, { Km2PerS => "km**2/s" });
1266
1267define_unit_type!(Km2s2, Km2s2Units, Km2PerS2, { Km2PerS2 => "km**2/s**2" });
1268
1269define_unit_type!(ManeuverFreq, NumPerYearUnits, PerYear, { PerYear => "#/yr" });
1270
1271define_unit_type!(Thrust, ThrustUnits, N, { N => "N" });
1272
1273define_unit_type!(Geomag, GeomagUnits, NanoTesla, { NanoTesla => "nT" });
1274
1275define_unit_type!(
1276 SolarFlux,
1277 SolarFluxUnits,
1278 Sfu,
1279 {
1280 Sfu => "SFU",
1281 JanskyScaled => "10**4 Jansky",
1282 WPerM2Hz => "10**-22 W/(m**2/Hz)",
1283 ErgPerSCm2Hz => "10**-19 erg/(s*cm**2*Hz)"
1284 }
1285);
1286
1287define_unit_type!(Moment, MomentUnits, KgM2, { KgM2 => "kg*m**2" });
1289
1290define_unit_type!(BallisticCoeff, BallisticCoeffUnits, KgPerM2, { KgPerM2 => "kg/m**2" });
1291
1292define_unit_enum!(PercentageUnits, Percent, { Percent => "%" });
1293
1294#[derive(Serialize, Debug, PartialEq, Clone)]
1295pub struct PercentageRequired {
1296 #[serde(rename = "$value")]
1297 pub value: f64,
1298 #[serde(rename = "@units")]
1299 pub units: PercentageUnits,
1300}
1301
1302impl<'de> serde::Deserialize<'de> for PercentageRequired {
1303 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
1304 where
1305 D: serde::Deserializer<'de>,
1306 {
1307 struct Visitor;
1308 impl<'de> serde::de::Visitor<'de> for Visitor {
1309 type Value = PercentageRequired;
1310 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1311 formatter.write_str("a float value or map with $value and @units")
1312 }
1313
1314 fn visit_f64<E>(self, v: f64) -> std::result::Result<Self::Value, E>
1315 where
1316 E: serde::de::Error,
1317 {
1318 PercentageRequired::new(v).map_err(E::custom)
1319 }
1320
1321 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
1322 where
1323 E: serde::de::Error,
1324 {
1325 let val = v.parse::<f64>().map_err(E::custom)?;
1326 PercentageRequired::new(val).map_err(E::custom)
1327 }
1328
1329 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
1330 where
1331 A: serde::de::MapAccess<'de>,
1332 {
1333 let mut value = None;
1334 let mut units = None;
1335 while let Some(key) = map.next_key::<String>()? {
1336 if key == "$value" || key == "$text" {
1337 value = Some(map.next_value::<f64>()?);
1338 } else if key == "@units" {
1339 units = Some(map.next_value::<PercentageUnits>()?);
1340 } else {
1341 let _ = map.next_value::<serde::de::IgnoredAny>()?;
1342 }
1343 }
1344 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
1345 let mut s = PercentageRequired::new(value).map_err(serde::de::Error::custom)?;
1346 if let Some(u) = units {
1347 s.units = u;
1348 }
1349 Ok(s)
1350 }
1351 }
1352 deserializer.deserialize_any(Visitor)
1353 }
1354}
1355impl PercentageRequired {
1356 pub fn new(value: f64) -> Result<Self> {
1357 if !(0.0..=100.0).contains(&value) {
1358 return Err(crate::error::ValidationError::OutOfRange {
1359 name: "PercentageRequired".into(),
1360 value: value.to_string(),
1361 expected: "[0, 100]".into(),
1362 line: None,
1363 }
1364 .into());
1365 }
1366 Ok(Self {
1367 value,
1368 units: PercentageUnits::Percent,
1369 })
1370 }
1371}
1372impl std::fmt::Display for PercentageRequired {
1373 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1374 write!(f, "{}", self.value)
1375 }
1376}
1377impl FromKvnFloat for PercentageRequired {
1378 fn from_kvn_float(value: f64, _unit: Option<&str>) -> Result<Self> {
1379 Self::new(value)
1380 }
1381}
1382
1383#[derive(Serialize, Debug, PartialEq, Clone)]
1384pub struct Probability {
1385 #[serde(rename = "$value")]
1386 pub value: f64,
1387}
1388
1389impl std::str::FromStr for Probability {
1390 type Err = crate::error::CcsdsNdmError;
1391 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1392 let val = s.parse::<f64>()?;
1393 Self::new(val)
1394 }
1395}
1396
1397impl<'de> serde::Deserialize<'de> for Probability {
1398 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
1399 where
1400 D: serde::Deserializer<'de>,
1401 {
1402 struct ProbabilityVisitor;
1403
1404 impl<'de> serde::de::Visitor<'de> for ProbabilityVisitor {
1405 type Value = Probability;
1406
1407 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1408 formatter.write_str("a primitive value or a map with $value")
1409 }
1410
1411 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
1412 where
1413 E: serde::de::Error,
1414 {
1415 v.parse::<Probability>().map_err(E::custom)
1416 }
1417
1418 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
1419 where
1420 A: serde::de::MapAccess<'de>,
1421 {
1422 let mut value = None;
1423
1424 while let Some(key) = map.next_key::<String>()? {
1425 if key == "$value" || key == "$text" {
1426 value = Some(map.next_value()?);
1427 } else {
1428 let _: serde::de::IgnoredAny = map.next_value()?;
1429 }
1430 }
1431
1432 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
1433 Probability::new(value).map_err(serde::de::Error::custom)
1434 }
1435 }
1436
1437 deserializer.deserialize_any(ProbabilityVisitor)
1438 }
1439}
1440
1441impl Probability {
1442 pub fn new(value: f64) -> Result<Self> {
1443 if !(0.0..=1.0).contains(&value) {
1444 return Err(crate::error::ValidationError::OutOfRange {
1445 name: "Probability".into(),
1446 value: value.to_string(),
1447 expected: "[0, 1]".into(),
1448 line: None,
1449 }
1450 .into());
1451 }
1452 Ok(Self { value })
1453 }
1454}
1455
1456impl std::fmt::Display for Probability {
1457 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1458 write!(f, "{}", self.value)
1459 }
1460}
1461
1462impl FromKvnFloat for Probability {
1463 fn from_kvn_float(value: f64, _unit: Option<&str>) -> Result<Self> {
1464 Self::new(value)
1465 }
1466}
1467
1468#[derive(Serialize, Debug, PartialEq, Clone, Copy)]
1470pub struct NonNegativeDouble {
1471 #[serde(rename = "$value")]
1472 pub value: f64,
1473}
1474
1475impl<'de> serde::Deserialize<'de> for NonNegativeDouble {
1476 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
1477 where
1478 D: serde::Deserializer<'de>,
1479 {
1480 struct NonNegativeDoubleVisitor;
1481
1482 impl<'de> serde::de::Visitor<'de> for NonNegativeDoubleVisitor {
1483 type Value = NonNegativeDouble;
1484
1485 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1486 formatter.write_str("a primitive value or a map with $value")
1487 }
1488
1489 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
1490 where
1491 E: serde::de::Error,
1492 {
1493 v.parse::<NonNegativeDouble>().map_err(E::custom)
1494 }
1495
1496 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
1497 where
1498 A: serde::de::MapAccess<'de>,
1499 {
1500 let mut value = None;
1501
1502 while let Some(key) = map.next_key::<String>()? {
1503 if key == "$value" || key == "$text" {
1504 value = Some(map.next_value()?);
1505 } else {
1506 let _: serde::de::IgnoredAny = map.next_value()?;
1507 }
1508 }
1509
1510 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
1511 NonNegativeDouble::new(value).map_err(serde::de::Error::custom)
1512 }
1513 }
1514
1515 deserializer.deserialize_any(NonNegativeDoubleVisitor)
1516 }
1517}
1518
1519impl NonNegativeDouble {
1520 pub fn new(value: f64) -> Result<Self> {
1521 if value < 0.0 {
1522 return Err(crate::error::ValidationError::OutOfRange {
1523 name: "NonNegativeDouble".into(),
1524 value: value.to_string(),
1525 expected: ">= 0".into(),
1526 line: None,
1527 }
1528 .into());
1529 }
1530 Ok(Self { value })
1531 }
1532}
1533
1534impl std::str::FromStr for NonNegativeDouble {
1535 type Err = CcsdsNdmError;
1536 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1537 let v: f64 = s.parse().map_err(CcsdsNdmError::from)?;
1538 Self::new(v)
1539 }
1540}
1541
1542impl std::fmt::Display for NonNegativeDouble {
1543 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1544 write!(f, "{}", self.value)
1545 }
1546}
1547
1548impl FromKvnFloat for NonNegativeDouble {
1549 fn from_kvn_float(value: f64, _unit: Option<&str>) -> Result<Self> {
1550 Self::new(value)
1551 }
1552}
1553
1554#[derive(Serialize, Debug, PartialEq, Clone, Copy)]
1556pub struct PositiveInteger {
1557 #[serde(rename = "$value")]
1558 pub value: u32,
1559}
1560
1561impl<'de> serde::Deserialize<'de> for PositiveInteger {
1562 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
1563 where
1564 D: serde::Deserializer<'de>,
1565 {
1566 struct PositiveIntegerVisitor;
1567
1568 impl<'de> serde::de::Visitor<'de> for PositiveIntegerVisitor {
1569 type Value = PositiveInteger;
1570
1571 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1572 formatter.write_str("a primitive value or a map with $value")
1573 }
1574
1575 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
1576 where
1577 E: serde::de::Error,
1578 {
1579 v.parse::<PositiveInteger>().map_err(E::custom)
1580 }
1581
1582 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
1583 where
1584 A: serde::de::MapAccess<'de>,
1585 {
1586 let mut value = None;
1587
1588 while let Some(key) = map.next_key::<String>()? {
1589 if key == "$value" || key == "$text" {
1590 value = Some(map.next_value()?);
1591 } else {
1592 let _: serde::de::IgnoredAny = map.next_value()?;
1593 }
1594 }
1595
1596 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
1597 PositiveInteger::new(value).map_err(serde::de::Error::custom)
1598 }
1599 }
1600
1601 deserializer.deserialize_any(PositiveIntegerVisitor)
1602 }
1603}
1604
1605impl PositiveInteger {
1606 pub fn new(value: u32) -> Result<Self> {
1607 if value == 0 {
1608 return Err(crate::error::ValidationError::OutOfRange {
1609 name: "PositiveInteger".into(),
1610 value: value.to_string(),
1611 expected: "> 0".into(),
1612 line: None,
1613 }
1614 .into());
1615 }
1616 Ok(Self { value })
1617 }
1618}
1619
1620impl std::str::FromStr for PositiveInteger {
1621 type Err = CcsdsNdmError;
1622 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1623 let v: u32 = s.parse().map_err(CcsdsNdmError::from)?;
1624 Self::new(v)
1625 }
1626}
1627
1628#[derive(Serialize, Debug, PartialEq, Clone, Copy)]
1630pub struct InterpolationDegree(pub std::num::NonZeroU32);
1631
1632impl std::str::FromStr for InterpolationDegree {
1633 type Err = crate::error::CcsdsNdmError;
1634 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1635 let val = s.parse::<u32>()?;
1636 let nz = std::num::NonZeroU32::new(val).ok_or_else(|| {
1637 crate::error::ValidationError::OutOfRange {
1638 name: "InterpolationDegree".into(),
1639 value: val.to_string(),
1640 expected: "> 0".into(),
1641 line: None,
1642 }
1643 })?;
1644 Ok(Self(nz))
1645 }
1646}
1647
1648impl std::fmt::Display for InterpolationDegree {
1649 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1650 write!(f, "{}", self.0)
1651 }
1652}
1653
1654impl<'de> serde::Deserialize<'de> for InterpolationDegree {
1655 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
1656 where
1657 D: serde::Deserializer<'de>,
1658 {
1659 struct InterpolationDegreeVisitor;
1660
1661 impl<'de> serde::de::Visitor<'de> for InterpolationDegreeVisitor {
1662 type Value = InterpolationDegree;
1663
1664 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1665 formatter.write_str("a primitive value or a map with $value")
1666 }
1667
1668 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
1669 where
1670 E: serde::de::Error,
1671 {
1672 v.parse::<InterpolationDegree>().map_err(E::custom)
1673 }
1674
1675 fn visit_u32<E>(self, v: u32) -> std::result::Result<Self::Value, E>
1676 where
1677 E: serde::de::Error,
1678 {
1679 std::num::NonZeroU32::new(v)
1680 .map(InterpolationDegree)
1681 .ok_or_else(|| E::custom("expected non-zero u32"))
1682 }
1683
1684 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
1685 where
1686 A: serde::de::MapAccess<'de>,
1687 {
1688 let mut value = None;
1689
1690 while let Some(key) = map.next_key::<String>()? {
1691 if key == "$value" || key == "$text" {
1692 value = Some(map.next_value::<u32>()?);
1693 } else {
1694 let _: serde::de::IgnoredAny = map.next_value()?;
1695 }
1696 }
1697
1698 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
1699 std::num::NonZeroU32::new(value)
1700 .map(InterpolationDegree)
1701 .ok_or_else(|| serde::de::Error::custom("expected non-zero u32"))
1702 }
1703 }
1704
1705 deserializer.deserialize_any(InterpolationDegreeVisitor)
1706 }
1707}
1708
1709impl From<std::num::NonZeroU32> for InterpolationDegree {
1710 fn from(val: std::num::NonZeroU32) -> Self {
1711 Self(val)
1712 }
1713}
1714
1715impl From<InterpolationDegree> for std::num::NonZeroU32 {
1716 fn from(val: InterpolationDegree) -> Self {
1717 val.0
1718 }
1719}
1720
1721impl std::fmt::Display for PositiveInteger {
1722 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1723 write!(f, "{}", self.value)
1724 }
1725}
1726
1727impl From<u32> for PositiveInteger {
1728 fn from(value: u32) -> Self {
1729 Self { value }
1730 }
1731}
1732
1733#[derive(Serialize, Debug, PartialEq, Clone, Copy)]
1735pub struct ElementSetNo {
1736 #[serde(rename = "$value")]
1737 pub value: u32,
1738}
1739
1740impl std::str::FromStr for ElementSetNo {
1741 type Err = crate::error::CcsdsNdmError;
1742 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1743 let v: u32 = s.parse().map_err(CcsdsNdmError::from)?;
1744 Self::new(v)
1745 }
1746}
1747
1748impl<'de> serde::Deserialize<'de> for ElementSetNo {
1749 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
1750 where
1751 D: serde::Deserializer<'de>,
1752 {
1753 struct ElementSetNoVisitor;
1754
1755 impl<'de> serde::de::Visitor<'de> for ElementSetNoVisitor {
1756 type Value = ElementSetNo;
1757
1758 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
1759 formatter.write_str("a primitive value or a map with $value")
1760 }
1761
1762 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
1763 where
1764 E: serde::de::Error,
1765 {
1766 v.parse::<ElementSetNo>().map_err(E::custom)
1767 }
1768
1769 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
1770 where
1771 A: serde::de::MapAccess<'de>,
1772 {
1773 let mut value = None;
1774
1775 while let Some(key) = map.next_key::<String>()? {
1776 if key == "$value" || key == "$text" {
1777 value = Some(map.next_value()?);
1778 } else {
1779 let _: serde::de::IgnoredAny = map.next_value()?;
1780 }
1781 }
1782
1783 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
1784 ElementSetNo::new(value).map_err(serde::de::Error::custom)
1785 }
1786 }
1787
1788 deserializer.deserialize_any(ElementSetNoVisitor)
1789 }
1790}
1791
1792impl ElementSetNo {
1793 pub fn new(value: u32) -> Result<Self> {
1794 if value > 9999 {
1795 return Err(crate::error::ValidationError::OutOfRange {
1796 name: "ElementSetNo".into(),
1797 value: value.to_string(),
1798 expected: "[0, 9999]".into(),
1799 line: None,
1800 }
1801 .into());
1802 }
1803 Ok(Self { value })
1804 }
1805}
1806
1807impl std::fmt::Display for ElementSetNo {
1808 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1809 write!(f, "{}", self.value)
1810 }
1811}
1812
1813impl From<u32> for ElementSetNo {
1814 fn from(value: u32) -> Self {
1815 Self { value }
1816 }
1817}
1818
1819#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
1821pub struct DeltaMass {
1822 #[serde(rename = "$value")]
1823 pub value: f64,
1824 #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
1825 pub units: Option<MassUnits>,
1826}
1827impl DeltaMass {
1828 pub fn new(value: f64, units: Option<MassUnits>) -> Result<Self> {
1829 if value >= 0.0 {
1830 return Err(crate::error::ValidationError::OutOfRange {
1831 name: "DeltaMass".into(),
1832 value: value.to_string(),
1833 expected: "< 0".into(),
1834 line: None,
1835 }
1836 .into());
1837 }
1838 Ok(Self { value, units })
1839 }
1840}
1841
1842impl FromKvnFloat for DeltaMass {
1843 fn from_kvn_float(value: f64, unit: Option<&str>) -> Result<Self> {
1844 let uv = UnitValue::<f64, MassUnits>::from_kvn_float(value, unit)?;
1845 Self::new(uv.value, uv.units)
1846 }
1847}
1848
1849#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
1850pub struct DeltaMassZ {
1851 #[serde(rename = "$value")]
1852 pub value: f64,
1853 #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
1854 pub units: Option<MassUnits>,
1855}
1856impl DeltaMassZ {
1857 pub fn new(value: f64, units: Option<MassUnits>) -> Result<Self> {
1858 if value > 0.0 {
1859 return Err(crate::error::ValidationError::OutOfRange {
1860 name: "DeltaMassZ".into(),
1861 value: value.to_string(),
1862 expected: "<= 0".into(),
1863 line: None,
1864 }
1865 .into());
1866 }
1867 Ok(Self { value, units })
1868 }
1869
1870 pub fn to_unit_value(&self) -> UnitValue<f64, MassUnits> {
1871 UnitValue {
1872 value: self.value,
1873 units: self.units.clone(),
1874 }
1875 }
1876}
1877
1878impl FromKvnFloat for DeltaMassZ {
1879 fn from_kvn_float(value: f64, unit: Option<&str>) -> Result<Self> {
1880 let uv = UnitValue::<f64, MassUnits>::from_kvn_float(value, unit)?;
1881 Self::new(uv.value, uv.units)
1882 }
1883}
1884
1885define_unit_type!(QuaternionDotComponent, QuaternionDotUnits, PerS, { PerS => "1/s" });
1887
1888define_unit_enum!(LatLonUnits, Deg, { Deg => "deg" });
1890pub type Latitude = UnitValue<f64, LatLonUnits>;
1891pub type Longitude = UnitValue<f64, LatLonUnits>;
1892pub type Altitude = UnitValue<f64, LengthUnits>;
1893
1894#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
1895pub struct LatitudeRequired {
1896 #[serde(rename = "$value")]
1897 pub value: f64,
1898 #[serde(rename = "@units")]
1899 pub units: LatLonUnits,
1900}
1901impl LatitudeRequired {
1902 pub fn new(value: f64) -> Result<Self> {
1903 if !(-90.0..=90.0).contains(&value) {
1904 return Err(crate::error::ValidationError::OutOfRange {
1905 name: "Latitude".into(),
1906 value: value.to_string(),
1907 expected: "[-90, 90]".into(),
1908 line: None,
1909 }
1910 .into());
1911 }
1912 Ok(Self {
1913 value,
1914 units: LatLonUnits::Deg,
1915 })
1916 }
1917}
1918impl std::fmt::Display for LatitudeRequired {
1919 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1920 write!(f, "{}", self.value)
1921 }
1922}
1923
1924impl std::str::FromStr for LatitudeRequired {
1925 type Err = CcsdsNdmError;
1926 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1927 let v: f64 = s.parse().map_err(CcsdsNdmError::from)?;
1928 Self::new(v)
1929 }
1930}
1931
1932impl FromKvnFloat for LatitudeRequired {
1933 fn from_kvn_float(value: f64, _unit: Option<&str>) -> Result<Self> {
1934 Self::new(value)
1935 }
1936}
1937
1938#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
1939pub struct LongitudeRequired {
1940 #[serde(rename = "$value")]
1941 pub value: f64,
1942 #[serde(rename = "@units")]
1943 pub units: LatLonUnits,
1944}
1945impl LongitudeRequired {
1946 pub fn new(value: f64) -> Result<Self> {
1947 if !(-180.0..=180.0).contains(&value) {
1948 return Err(crate::error::ValidationError::OutOfRange {
1949 name: "Longitude".into(),
1950 value: value.to_string(),
1951 expected: "[-180, 180]".into(),
1952 line: None,
1953 }
1954 .into());
1955 }
1956 Ok(Self {
1957 value,
1958 units: LatLonUnits::Deg,
1959 })
1960 }
1961}
1962impl std::fmt::Display for LongitudeRequired {
1963 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1964 write!(f, "{}", self.value)
1965 }
1966}
1967
1968impl std::str::FromStr for LongitudeRequired {
1969 type Err = CcsdsNdmError;
1970 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
1971 let v: f64 = s.parse().map_err(CcsdsNdmError::from)?;
1972 Self::new(v)
1973 }
1974}
1975
1976impl FromKvnFloat for LongitudeRequired {
1977 fn from_kvn_float(value: f64, _unit: Option<&str>) -> Result<Self> {
1978 Self::new(value)
1979 }
1980}
1981
1982define_unit_type!(Torque, TorqueUnits, Nm, { Nm => "N*m" });
1984
1985#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
1987pub struct Vector3 {
1988 #[serde(rename = "$value", with = "crate::utils::vec_f64_space_sep")]
1989 pub elements: Vec<f64>, #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
1991 pub units: Option<LengthUnits>,
1992}
1993impl Vector3 {
1994 pub fn new(elements: [f64; 3], units: Option<LengthUnits>) -> Self {
1995 Self {
1996 elements: elements.to_vec(),
1997 units,
1998 }
1999 }
2000}
2001
2002#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2004pub struct TargetMomentum {
2005 #[serde(rename = "$value", with = "crate::utils::vec_f64_space_sep")]
2006 pub elements: Vec<f64>, #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
2008 pub units: Option<AngMomentumUnits>,
2009}
2010impl TargetMomentum {
2011 pub fn new(elements: [f64; 3], units: Option<AngMomentumUnits>) -> Self {
2012 Self {
2013 elements: elements.to_vec(),
2014 units,
2015 }
2016 }
2017}
2018
2019#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2023pub enum ObjectDescription {
2024 #[serde(rename = "PAYLOAD")]
2025 Payload,
2026 #[serde(rename = "payload")]
2027 PayloadLower,
2028 #[serde(rename = "ROCKET BODY")]
2029 RocketBody,
2030 #[serde(rename = "rocket body")]
2031 RocketBodyLower,
2032 #[serde(rename = "DEBRIS")]
2033 Debris,
2034 #[serde(rename = "debris")]
2035 DebrisLower,
2036 #[serde(rename = "UNKNOWN")]
2037 Unknown,
2038 #[serde(rename = "unknown")]
2039 UnknownLower,
2040 #[serde(rename = "OTHER")]
2041 Other,
2042 #[serde(rename = "other")]
2043 OtherLower,
2044}
2045
2046impl std::str::FromStr for ObjectDescription {
2047 type Err = crate::error::EnumParseError;
2048 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2049 match s.to_uppercase().as_str() {
2050 "PAYLOAD" => Ok(Self::Payload),
2051 "ROCKET BODY" => Ok(Self::RocketBody),
2052 "DEBRIS" => Ok(Self::Debris),
2053 "UNKNOWN" => Ok(Self::Unknown),
2054 "OTHER" => Ok(Self::Other),
2055 _ => Ok(Self::Other),
2056 }
2057 }
2058}
2059impl std::fmt::Display for ObjectDescription {
2060 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2061 let s = match self {
2062 ObjectDescription::Payload | ObjectDescription::PayloadLower => "PAYLOAD",
2063 ObjectDescription::RocketBody | ObjectDescription::RocketBodyLower => "ROCKET BODY",
2064 ObjectDescription::Debris | ObjectDescription::DebrisLower => "DEBRIS",
2065 ObjectDescription::Unknown | ObjectDescription::UnknownLower => "UNKNOWN",
2066 ObjectDescription::Other | ObjectDescription::OtherLower => "OTHER",
2067 };
2068 write!(f, "{}", s)
2069 }
2070}
2071
2072#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2073pub enum RotSeq {
2074 #[serde(rename = "XYX")]
2075 XYX,
2076 #[serde(rename = "XYZ")]
2077 XYZ,
2078 #[serde(rename = "XZX")]
2079 XZX,
2080 #[serde(rename = "XZY")]
2081 XZY,
2082 #[serde(rename = "YXY")]
2083 YXY,
2084 #[serde(rename = "YXZ")]
2085 YXZ,
2086 #[serde(rename = "YZX")]
2087 YZX,
2088 #[serde(rename = "YZY")]
2089 YZY,
2090 #[serde(rename = "ZXY")]
2091 ZXY,
2092 #[serde(rename = "ZXZ")]
2093 ZXZ,
2094 #[serde(rename = "ZYX")]
2095 ZYX,
2096 #[serde(rename = "ZYZ")]
2097 ZYZ,
2098}
2099
2100impl std::str::FromStr for RotSeq {
2101 type Err = crate::error::EnumParseError;
2102 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2103 match s {
2104 "XYX" => Ok(Self::XYX),
2105 "XYZ" => Ok(Self::XYZ),
2106 "XZX" => Ok(Self::XZX),
2107 "XZY" => Ok(Self::XZY),
2108 "YXY" => Ok(Self::YXY),
2109 "YXZ" => Ok(Self::YXZ),
2110 "YZX" => Ok(Self::YZX),
2111 "YZY" => Ok(Self::YZY),
2112 "ZXY" => Ok(Self::ZXY),
2113 "ZXZ" => Ok(Self::ZXZ),
2114 "ZYX" => Ok(Self::ZYX),
2115 "ZYZ" => Ok(Self::ZYZ),
2116 "121" => Ok(Self::XYX),
2117 "123" => Ok(Self::XYZ),
2118 "131" => Ok(Self::XZX),
2119 "132" => Ok(Self::XZY),
2120 "212" => Ok(Self::YXY),
2121 "213" => Ok(Self::YXZ),
2122 "231" => Ok(Self::YZX),
2123 "232" => Ok(Self::YZY),
2124 "312" => Ok(Self::ZXY),
2125 "313" => Ok(Self::ZXZ),
2126 "321" => Ok(Self::ZYX),
2127 "323" => Ok(Self::ZYZ),
2128 _ => Err(crate::error::EnumParseError {
2129 field: "EULER_ROT_SEQ",
2130 value: s.to_string(),
2131 expected: "XYX, XYZ, XZX, XZY, YXY, YXZ, YZX, YZY, ZXY, ZXZ, ZYX, ZYZ, or numeric equivalents",
2132 }),
2133 }
2134 }
2135}
2136
2137impl std::fmt::Display for RotSeq {
2138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2139 match self {
2140 Self::XYX => write!(f, "XYX"),
2141 Self::XYZ => write!(f, "XYZ"),
2142 Self::XZX => write!(f, "XZX"),
2143 Self::XZY => write!(f, "XZY"),
2144 Self::YXY => write!(f, "YXY"),
2145 Self::YXZ => write!(f, "YXZ"),
2146 Self::YZX => write!(f, "YZX"),
2147 Self::YZY => write!(f, "YZY"),
2148 Self::ZXY => write!(f, "ZXY"),
2149 Self::ZXZ => write!(f, "ZXZ"),
2150 Self::ZYX => write!(f, "ZYX"),
2151 Self::ZYZ => write!(f, "ZYZ"),
2152 }
2153 }
2154}
2155
2156#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2157pub enum AdMethod {
2158 #[serde(rename = "EKF")]
2159 Ekf,
2160 #[serde(rename = "ekf")]
2161 EkfLower,
2162 #[serde(rename = "TRIAD")]
2163 Triad,
2164 #[serde(rename = "triad")]
2165 TriadLower,
2166 #[serde(rename = "QUEST")]
2167 Quest,
2168 #[serde(rename = "quest")]
2169 QuestLower,
2170 #[serde(rename = "BATCH")]
2171 Batch,
2172 #[serde(rename = "batch")]
2173 BatchLower,
2174 #[serde(rename = "Q_METHOD")]
2175 QMethod,
2176 #[serde(rename = "q_method")]
2177 QMethodLower,
2178 #[serde(rename = "FILTER_SMOOTHER")]
2179 FilterSmoother,
2180 #[serde(rename = "filter_smoother")]
2181 FilterSmootherLower,
2182 #[serde(rename = "OTHER")]
2183 Other,
2184 #[serde(rename = "other")]
2185 OtherLower,
2186}
2187
2188#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2189pub enum YesNo {
2190 #[serde(rename = "YES")]
2191 Yes,
2192 #[serde(rename = "yes")]
2193 YesLower,
2194 #[serde(rename = "NO")]
2195 No,
2196 #[serde(rename = "no")]
2197 NoLower,
2198}
2199impl std::fmt::Display for YesNo {
2200 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2201 let s = match self {
2202 YesNo::Yes | YesNo::YesLower => "YES",
2203 YesNo::No | YesNo::NoLower => "NO",
2204 };
2205 write!(f, "{}", s)
2206 }
2207}
2208impl std::str::FromStr for YesNo {
2209 type Err = crate::error::EnumParseError;
2210 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2211 match s {
2212 "YES" | "yes" => Ok(YesNo::Yes),
2213 "NO" | "no" => Ok(YesNo::No),
2214 _ => Err(crate::error::EnumParseError {
2215 field: "YES/NO",
2216 value: s.to_string(),
2217 expected: "YES or NO",
2218 }),
2219 }
2220 }
2221}
2222
2223#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2225pub enum TrajBasis {
2226 #[serde(rename = "PREDICTED")]
2228 Predicted,
2229 #[serde(rename = "DETERMINED")]
2234 Determined,
2235 #[serde(rename = "TELEMETRY")]
2239 Telemetry,
2240 #[serde(rename = "SIMULATED")]
2243 Simulated,
2244 #[serde(rename = "OTHER")]
2246 Other,
2247}
2248
2249impl std::fmt::Display for TrajBasis {
2250 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2251 match self {
2252 Self::Predicted => write!(f, "PREDICTED"),
2253 Self::Determined => write!(f, "DETERMINED"),
2254 Self::Telemetry => write!(f, "TELEMETRY"),
2255 Self::Simulated => write!(f, "SIMULATED"),
2256 Self::Other => write!(f, "OTHER"),
2257 }
2258 }
2259}
2260
2261impl std::str::FromStr for TrajBasis {
2262 type Err = crate::error::EnumParseError;
2263 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2264 match s.to_uppercase().as_str() {
2265 "PREDICTED" => Ok(Self::Predicted),
2266 "DETERMINED" => Ok(Self::Determined),
2267 "TELEMETRY" => Ok(Self::Telemetry),
2268 "SIMULATED" => Ok(Self::Simulated),
2269 "OTHER" => Ok(Self::Other),
2270 _ => Err(crate::error::EnumParseError {
2271 field: "TRAJ_BASIS",
2272 value: s.to_string(),
2273 expected: "PREDICTED, DETERMINED, TELEMETRY, SIMULATED, or OTHER",
2274 }),
2275 }
2276 }
2277}
2278
2279#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2280pub enum RevNumBasis {
2281 #[serde(rename = "0")]
2282 Zero,
2283 #[serde(rename = "1")]
2284 One,
2285}
2286
2287impl std::fmt::Display for RevNumBasis {
2288 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2289 match self {
2290 Self::Zero => write!(f, "0"),
2291 Self::One => write!(f, "1"),
2292 }
2293 }
2294}
2295
2296impl std::str::FromStr for RevNumBasis {
2297 type Err = crate::error::EnumParseError;
2298 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2299 match s {
2300 "0" => Ok(Self::Zero),
2301 "1" => Ok(Self::One),
2302 _ => Err(crate::error::EnumParseError {
2303 field: "ORB_REVNUM_BASIS",
2304 value: s.to_string(),
2305 expected: "0 or 1",
2306 }),
2307 }
2308 }
2309}
2310
2311#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2313pub enum CovBasis {
2314 #[serde(rename = "PREDICTED")]
2316 Predicted,
2317 #[serde(rename = "DETERMINED")]
2322 Determined,
2323 #[serde(rename = "EMPIRICAL")]
2326 Empirical,
2327 #[serde(rename = "SIMULATED")]
2331 Simulated,
2332 #[serde(rename = "OTHER")]
2334 Other,
2335}
2336
2337impl std::fmt::Display for CovBasis {
2338 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2339 match self {
2340 Self::Predicted => write!(f, "PREDICTED"),
2341 Self::Determined => write!(f, "DETERMINED"),
2342 Self::Empirical => write!(f, "EMPIRICAL"),
2343 Self::Simulated => write!(f, "SIMULATED"),
2344 Self::Other => write!(f, "OTHER"),
2345 }
2346 }
2347}
2348
2349impl std::str::FromStr for CovBasis {
2350 type Err = crate::error::EnumParseError;
2351 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2352 match s.to_uppercase().as_str() {
2353 "PREDICTED" => Ok(Self::Predicted),
2354 "DETERMINED" => Ok(Self::Determined),
2355 "EMPIRICAL" => Ok(Self::Empirical),
2356 "SIMULATED" => Ok(Self::Simulated),
2357 "OTHER" => Ok(Self::Other),
2358 _ => Err(crate::error::EnumParseError {
2359 field: "COV_BASIS",
2360 value: s.to_string(),
2361 expected: "PREDICTED, DETERMINED, EMPIRICAL, SIMULATED, or OTHER",
2362 }),
2363 }
2364 }
2365}
2366
2367#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2369pub enum ManBasis {
2370 #[serde(rename = "CANDIDATE")]
2373 Candidate,
2374 #[serde(rename = "PLANNED")]
2377 Planned,
2378 #[serde(rename = "ANTICIPATED")]
2382 Anticipated,
2383 #[serde(rename = "TELEMETRY")]
2387 Telemetry,
2388 #[serde(rename = "DETERMINED")]
2392 Determined,
2393 #[serde(rename = "SIMULATED")]
2396 Simulated,
2397 #[serde(rename = "OTHER")]
2399 Other,
2400}
2401
2402impl std::fmt::Display for ManBasis {
2403 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2404 match self {
2405 Self::Candidate => write!(f, "CANDIDATE"),
2406 Self::Planned => write!(f, "PLANNED"),
2407 Self::Anticipated => write!(f, "ANTICIPATED"),
2408 Self::Telemetry => write!(f, "TELEMETRY"),
2409 Self::Determined => write!(f, "DETERMINED"),
2410 Self::Simulated => write!(f, "SIMULATED"),
2411 Self::Other => write!(f, "OTHER"),
2412 }
2413 }
2414}
2415
2416impl std::str::FromStr for ManBasis {
2417 type Err = crate::error::EnumParseError;
2418 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2419 match s.to_uppercase().as_str() {
2420 "CANDIDATE" => Ok(Self::Candidate),
2421 "PLANNED" => Ok(Self::Planned),
2422 "ANTICIPATED" => Ok(Self::Anticipated),
2423 "TELEMETRY" => Ok(Self::Telemetry),
2424 "DETERMINED" => Ok(Self::Determined),
2425 "SIMULATED" => Ok(Self::Simulated),
2426 "OTHER" => Ok(Self::Other),
2427 _ => Err(crate::error::EnumParseError {
2428 field: "MAN_BASIS",
2429 value: s.to_string(),
2430 expected:
2431 "CANDIDATE, PLANNED, ANTICIPATED, TELEMETRY, DETERMINED, SIMULATED, or OTHER",
2432 }),
2433 }
2434 }
2435}
2436
2437#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)]
2439pub enum ManDc {
2440 #[default]
2442 #[serde(rename = "CONTINUOUS")]
2443 Continuous,
2444 #[serde(rename = "TIME")]
2447 Time,
2448 #[serde(rename = "TIME_AND_ANGLE")]
2451 TimeAndAngle,
2452}
2453
2454impl std::fmt::Display for ManDc {
2455 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2456 match self {
2457 Self::Continuous => write!(f, "CONTINUOUS"),
2458 Self::Time => write!(f, "TIME"),
2459 Self::TimeAndAngle => write!(f, "TIME_AND_ANGLE"),
2460 }
2461 }
2462}
2463
2464impl std::str::FromStr for ManDc {
2465 type Err = crate::error::EnumParseError;
2466 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2467 match s.to_uppercase().as_str() {
2468 "CONTINUOUS" => Ok(Self::Continuous),
2469 "TIME" => Ok(Self::Time),
2470 "TIME_AND_ANGLE" => Ok(Self::TimeAndAngle),
2471 _ => Err(crate::error::EnumParseError {
2472 field: "DC_TYPE",
2473 value: s.to_string(),
2474 expected: "CONTINUOUS, TIME, or TIME_AND_ANGLE",
2475 }),
2476 }
2477 }
2478}
2479
2480#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)]
2482pub enum CovOrder {
2483 #[default]
2485 #[serde(rename = "LTM")]
2486 Ltm,
2487 #[serde(rename = "UTM")]
2489 Utm,
2490 #[serde(rename = "FULL")]
2492 Full,
2493 #[serde(rename = "LTMWCC")]
2496 LtmWcc,
2497 #[serde(rename = "UTMWCC")]
2500 UtmWcc,
2501}
2502
2503impl std::fmt::Display for CovOrder {
2504 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2505 match self {
2506 Self::Ltm => write!(f, "LTM"),
2507 Self::Utm => write!(f, "UTM"),
2508 Self::Full => write!(f, "FULL"),
2509 Self::LtmWcc => write!(f, "LTMWCC"),
2510 Self::UtmWcc => write!(f, "UTMWCC"),
2511 }
2512 }
2513}
2514
2515impl std::str::FromStr for CovOrder {
2516 type Err = crate::error::EnumParseError;
2517 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2518 match s.to_uppercase().as_str() {
2519 "LTM" => Ok(Self::Ltm),
2520 "UTM" => Ok(Self::Utm),
2521 "FULL" => Ok(Self::Full),
2522 "LTMWCC" => Ok(Self::LtmWcc),
2523 "UTMWCC" => Ok(Self::UtmWcc),
2524 _ => Err(crate::error::EnumParseError {
2525 field: "COV_ORDERING",
2526 value: s.to_string(),
2527 expected: "LTM, UTM, FULL, LTMWCC, or UTMWCC",
2528 }),
2529 }
2530 }
2531}
2532
2533#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2534pub enum ControlledType {
2535 #[serde(rename = "YES")]
2536 Yes,
2537 #[serde(rename = "yes")]
2538 YesLower,
2539 #[serde(rename = "NO")]
2540 No,
2541 #[serde(rename = "no")]
2542 NoLower,
2543 #[serde(rename = "UNKNOWN")]
2544 Unknown,
2545 #[serde(rename = "unknown")]
2546 UnknownLower,
2547}
2548impl std::fmt::Display for ControlledType {
2549 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2550 let s = match self {
2551 ControlledType::Yes | ControlledType::YesLower => "YES",
2552 ControlledType::No | ControlledType::NoLower => "NO",
2553 ControlledType::Unknown | ControlledType::UnknownLower => "UNKNOWN",
2554 };
2555 write!(f, "{}", s)
2556 }
2557}
2558impl std::str::FromStr for ControlledType {
2559 type Err = crate::error::EnumParseError;
2560 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2561 match s {
2562 "YES" | "yes" => Ok(ControlledType::Yes),
2563 "NO" | "no" => Ok(ControlledType::No),
2564 "UNKNOWN" | "unknown" => Ok(ControlledType::Unknown),
2565 _ => Err(crate::error::EnumParseError {
2566 field: "CONTROLLED_TYPE",
2567 value: s.to_string(),
2568 expected: "YES, NO, or UNKNOWN",
2569 }),
2570 }
2571 }
2572}
2573
2574define_unit_enum!(TimeUnits, Seconds, { Seconds => "s", Day => "d" });
2576
2577#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2578pub struct Duration {
2579 #[serde(rename = "$value")]
2580 pub value: f64, #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
2582 pub units: Option<TimeUnits>,
2583}
2584impl Duration {
2585 pub fn new(value: f64, units: Option<TimeUnits>) -> Result<Self> {
2586 if value < 0.0 {
2587 return Err(crate::error::ValidationError::OutOfRange {
2588 name: "Duration".into(),
2589 value: value.to_string(),
2590 expected: ">= 0".into(),
2591 line: None,
2592 }
2593 .into());
2594 }
2595 Ok(Self { value, units })
2596 }
2597 pub fn to_unit_value(&self) -> UnitValue<f64, TimeUnits> {
2598 UnitValue {
2599 value: self.value,
2600 units: self.units.clone(),
2601 }
2602 }
2603}
2604impl FromKvnFloat for Duration {
2605 fn from_kvn_float(value: f64, unit: Option<&str>) -> Result<Self> {
2606 let uv = UnitValue::<f64, TimeUnits>::from_kvn_float(value, unit)?;
2607 Self::new(uv.value, uv.units)
2608 }
2609}
2610#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2611pub struct RelTime {
2612 #[serde(rename = "$value")]
2613 pub value: f64, #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
2615 pub units: Option<TimeUnits>,
2616}
2617
2618#[derive(Serialize, Debug, PartialEq, Clone)]
2619pub struct TimeOffset {
2620 #[serde(rename = "$value")]
2621 pub value: f64, #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
2623 pub units: Option<TimeUnits>,
2624}
2625
2626impl std::str::FromStr for TimeOffset {
2627 type Err = crate::error::CcsdsNdmError;
2628 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2629 let val = s.parse::<f64>()?;
2630 Ok(Self {
2631 value: val,
2632 units: None,
2633 })
2634 }
2635}
2636
2637impl<'de> serde::Deserialize<'de> for TimeOffset {
2638 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
2639 where
2640 D: serde::Deserializer<'de>,
2641 {
2642 struct TimeOffsetVisitor;
2643
2644 impl<'de> serde::de::Visitor<'de> for TimeOffsetVisitor {
2645 type Value = TimeOffset;
2646
2647 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
2648 formatter.write_str("a primitive value or a map with $value and optionally @units")
2649 }
2650
2651 fn visit_str<E>(self, v: &str) -> std::result::Result<Self::Value, E>
2652 where
2653 E: serde::de::Error,
2654 {
2655 v.parse::<TimeOffset>().map_err(E::custom)
2656 }
2657
2658 fn visit_map<A>(self, mut map: A) -> std::result::Result<Self::Value, A::Error>
2659 where
2660 A: serde::de::MapAccess<'de>,
2661 {
2662 let mut value = None;
2663 let mut units = None;
2664
2665 while let Some(key) = map.next_key::<String>()? {
2666 if key == "$value" || key == "$text" {
2667 value = Some(map.next_value()?);
2668 } else if key == "@units" {
2669 units = Some(map.next_value()?);
2670 } else {
2671 let _: serde::de::IgnoredAny = map.next_value()?;
2672 }
2673 }
2674
2675 let value = value.ok_or_else(|| serde::de::Error::missing_field("$value"))?;
2676 Ok(TimeOffset { value, units })
2677 }
2678 }
2679
2680 deserializer.deserialize_any(TimeOffsetVisitor)
2681 }
2682}
2683
2684impl FromKvnFloat for TimeOffset {
2685 fn from_kvn_float(value: f64, unit: Option<&str>) -> Result<Self> {
2686 let uv = UnitValue::<f64, TimeUnits>::from_kvn_float(value, unit)?;
2687 Ok(TimeOffset {
2688 value: uv.value,
2689 units: uv.units,
2690 })
2691 }
2692}
2693impl TimeOffset {
2694 pub fn to_unit_value(&self) -> UnitValue<f64, TimeUnits> {
2695 UnitValue {
2696 value: self.value,
2697 units: self.units.clone(),
2698 }
2699 }
2700}
2701
2702#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2704#[serde(transparent)]
2705pub struct Inclination {
2706 pub angle: Angle, }
2708impl Inclination {
2709 pub fn new(value: f64, units: Option<AngleUnits>) -> Result<Self> {
2710 if !(0.0..=180.0).contains(&value) {
2711 return Err(crate::error::ValidationError::OutOfRange {
2712 name: "Inclination".into(),
2713 value: value.to_string(),
2714 expected: "[0, 180]".into(),
2715 line: None,
2716 }
2717 .into());
2718 }
2719 Ok(Self {
2720 angle: Angle { value, units },
2721 })
2722 }
2723 pub fn to_unit_value(&self) -> UnitValue<f64, AngleUnits> {
2724 UnitValue {
2725 value: self.angle.value,
2726 units: self.angle.units.clone(),
2727 }
2728 }
2729}
2730impl FromKvnFloat for Inclination {
2731 fn from_kvn_float(value: f64, unit: Option<&str>) -> Result<Self> {
2732 let uv = UnitValue::<f64, AngleUnits>::from_kvn_float(value, unit)?;
2733 Self::new(uv.value, uv.units)
2734 }
2735}
2736
2737#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2739pub enum AcmAttitudeType {
2740 #[serde(rename = "QUATERNION")]
2741 Quaternion,
2742 #[serde(rename = "quaternion")]
2743 QuaternionLower,
2744 #[serde(rename = "EULER_ANGLES")]
2745 EulerAngles,
2746 #[serde(rename = "euler_angles")]
2747 EulerAnglesLower,
2748 #[serde(rename = "DCM")]
2749 Dcm,
2750 #[serde(rename = "dcm")]
2751 DcmLower,
2752 #[serde(rename = "ANGVEL")]
2753 AngVel,
2754 #[serde(rename = "angvel")]
2755 AngVelLower,
2756 #[serde(rename = "Q_DOT")]
2757 QDot,
2758 #[serde(rename = "q_dot")]
2759 QDotLower,
2760 #[serde(rename = "EULER_RATE")]
2761 EulerRate,
2762 #[serde(rename = "euler_rate")]
2763 EulerRateLower,
2764 #[serde(rename = "GYRO_BIAS")]
2765 GyroBias,
2766 #[serde(rename = "gyro_bias")]
2767 GyroBiasLower,
2768}
2769
2770impl std::str::FromStr for AcmAttitudeType {
2771 type Err = crate::error::EnumParseError;
2772 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2773 match s {
2774 "QUATERNION" => Ok(Self::Quaternion),
2775 "quaternion" => Ok(Self::QuaternionLower),
2776 "EULER_ANGLES" => Ok(Self::EulerAngles),
2777 "euler_angles" => Ok(Self::EulerAnglesLower),
2778 "DCM" => Ok(Self::Dcm),
2779 "dcm" => Ok(Self::DcmLower),
2780 "ANGVEL" => Ok(Self::AngVel),
2781 "angvel" => Ok(Self::AngVelLower),
2782 "Q_DOT" => Ok(Self::QDot),
2783 "q_dot" => Ok(Self::QDotLower),
2784 "EULER_RATE" => Ok(Self::EulerRate),
2785 "euler_rate" => Ok(Self::EulerRateLower),
2786 "GYRO_BIAS" => Ok(Self::GyroBias),
2787 "gyro_bias" => Ok(Self::GyroBiasLower),
2788 _ => Err(crate::error::EnumParseError {
2789 field: "ATT_TYPE",
2790 value: s.to_string(),
2791 expected: "QUATERNION, EULER_ANGLES, DCM, ANGVEL, Q_DOT, EULER_RATE, or GYRO_BIAS",
2792 }),
2793 }
2794 }
2795}
2796
2797impl std::fmt::Display for AcmAttitudeType {
2798 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2799 let value = match self {
2800 Self::Quaternion | Self::QuaternionLower => "QUATERNION",
2801 Self::EulerAngles | Self::EulerAnglesLower => "EULER_ANGLES",
2802 Self::Dcm | Self::DcmLower => "DCM",
2803 Self::AngVel | Self::AngVelLower => "ANGVEL",
2804 Self::QDot | Self::QDotLower => "Q_DOT",
2805 Self::EulerRate | Self::EulerRateLower => "EULER_RATE",
2806 Self::GyroBias | Self::GyroBiasLower => "GYRO_BIAS",
2807 };
2808 write!(f, "{}", value)
2809 }
2810}
2811
2812#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2813pub enum AttRateType {
2814 #[serde(rename = "ANGVEL")]
2815 AngVel,
2816 #[serde(rename = "angvel")]
2817 AngVelLower,
2818 #[serde(rename = "Q_DOT")]
2819 QDot,
2820 #[serde(rename = "q_dot")]
2821 QDotLower,
2822 #[serde(rename = "EULER_RATE")]
2823 EulerRate,
2824 #[serde(rename = "euler_rate")]
2825 EulerRateLower,
2826 #[serde(rename = "GYRO_BIAS")]
2827 GyroBias,
2828 #[serde(rename = "gyro_bias")]
2829 GyroBiasLower,
2830}
2831
2832impl std::str::FromStr for AttRateType {
2833 type Err = crate::error::EnumParseError;
2834 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2835 match s {
2836 "ANGVEL" => Ok(Self::AngVel),
2837 "angvel" => Ok(Self::AngVelLower),
2838 "Q_DOT" => Ok(Self::QDot),
2839 "q_dot" => Ok(Self::QDotLower),
2840 "EULER_RATE" => Ok(Self::EulerRate),
2841 "euler_rate" => Ok(Self::EulerRateLower),
2842 "GYRO_BIAS" => Ok(Self::GyroBias),
2843 "gyro_bias" => Ok(Self::GyroBiasLower),
2844 _ => Err(crate::error::EnumParseError {
2845 field: "RATE_TYPE",
2846 value: s.to_string(),
2847 expected: "ANGVEL, Q_DOT, EULER_RATE, or GYRO_BIAS",
2848 }),
2849 }
2850 }
2851}
2852
2853impl std::fmt::Display for AttRateType {
2854 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2855 let value = match self {
2856 Self::AngVel | Self::AngVelLower => "ANGVEL",
2857 Self::QDot | Self::QDotLower => "Q_DOT",
2858 Self::EulerRate | Self::EulerRateLower => "EULER_RATE",
2859 Self::GyroBias | Self::GyroBiasLower => "GYRO_BIAS",
2860 };
2861 write!(f, "{}", value)
2862 }
2863}
2864
2865#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2866pub enum AttBasisType {
2867 #[serde(rename = "PREDICTED")]
2868 Predicted,
2869 #[serde(rename = "predicted")]
2870 PredictedLower,
2871 #[serde(rename = "DETERMINED_GND")]
2872 DeterminedGnd,
2873 #[serde(rename = "determined_gnd")]
2874 DeterminedGndLower,
2875 #[serde(rename = "DETERMINED_OBC")]
2876 DeterminedObc,
2877 #[serde(rename = "determined_obc")]
2878 DeterminedObcLower,
2879 #[serde(rename = "SIMULATED")]
2880 Simulated,
2881 #[serde(rename = "simulated")]
2882 SimulatedLower,
2883}
2884
2885impl std::str::FromStr for AttBasisType {
2886 type Err = crate::error::EnumParseError;
2887 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2888 match s {
2889 "PREDICTED" => Ok(Self::Predicted),
2890 "predicted" => Ok(Self::PredictedLower),
2891 "DETERMINED_GND" => Ok(Self::DeterminedGnd),
2892 "determined_gnd" => Ok(Self::DeterminedGndLower),
2893 "DETERMINED_OBC" => Ok(Self::DeterminedObc),
2894 "determined_obc" => Ok(Self::DeterminedObcLower),
2895 "SIMULATED" => Ok(Self::Simulated),
2896 "simulated" => Ok(Self::SimulatedLower),
2897 _ => Err(crate::error::EnumParseError {
2898 field: "ATT_BASIS",
2899 value: s.to_string(),
2900 expected: "PREDICTED, DETERMINED_GND, DETERMINED_OBC, or SIMULATED",
2901 }),
2902 }
2903 }
2904}
2905
2906impl std::fmt::Display for AttBasisType {
2907 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2908 let value = match self {
2909 Self::Predicted | Self::PredictedLower => "PREDICTED",
2910 Self::DeterminedGnd | Self::DeterminedGndLower => "DETERMINED_GND",
2911 Self::DeterminedObc | Self::DeterminedObcLower => "DETERMINED_OBC",
2912 Self::Simulated | Self::SimulatedLower => "SIMULATED",
2913 };
2914 write!(f, "{}", value)
2915 }
2916}
2917
2918#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2919pub enum AcmCovarianceLineType {
2920 #[serde(rename = "ANGLE")]
2921 Angle,
2922 #[serde(rename = "angle")]
2923 AngleLower,
2924 #[serde(rename = "ANGLE_GYROBIAS")]
2925 AngleGyroBias,
2926 #[serde(rename = "angle_gyrobias")]
2927 AngleGyroBiasLower,
2928 #[serde(rename = "ANGLE_ANGVEL")]
2929 AngleAngVel,
2930 #[serde(rename = "angle_angvel")]
2931 AngleAngVelLower,
2932 #[serde(rename = "QUATERNION")]
2933 Quaternion,
2934 #[serde(rename = "quaternion")]
2935 QuaternionLower,
2936 #[serde(rename = "QUATERNION_GYROBIAS")]
2937 QuaternionGyroBias,
2938 #[serde(rename = "quaternion_gyrobias")]
2939 QuaternionGyroBiasLower,
2940 #[serde(rename = "QUATERNION_ANGVEL")]
2941 QuaternionAngVel,
2942 #[serde(rename = "quaternion_angvel")]
2943 QuaternionAngVelLower,
2944}
2945
2946impl std::str::FromStr for AcmCovarianceLineType {
2947 type Err = crate::error::EnumParseError;
2948 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
2949 match s {
2950 "ANGLE" => Ok(Self::Angle),
2951 "angle" => Ok(Self::AngleLower),
2952 "ANGLE_GYROBIAS" => Ok(Self::AngleGyroBias),
2953 "angle_gyrobias" => Ok(Self::AngleGyroBiasLower),
2954 "ANGLE_ANGVEL" => Ok(Self::AngleAngVel),
2955 "angle_angvel" => Ok(Self::AngleAngVelLower),
2956 "QUATERNION" => Ok(Self::Quaternion),
2957 "quaternion" => Ok(Self::QuaternionLower),
2958 "QUATERNION_GYROBIAS" => Ok(Self::QuaternionGyroBias),
2959 "quaternion_gyrobias" => Ok(Self::QuaternionGyroBiasLower),
2960 "QUATERNION_ANGVEL" => Ok(Self::QuaternionAngVel),
2961 "quaternion_angvel" => Ok(Self::QuaternionAngVelLower),
2962 _ => Err(crate::error::EnumParseError {
2963 field: "COV_TYPE",
2964 value: s.to_string(),
2965 expected: "ANGLE, ANGLE_GYROBIAS, ANGLE_ANGVEL, QUATERNION, QUATERNION_GYROBIAS, or QUATERNION_ANGVEL",
2966 }),
2967 }
2968 }
2969}
2970
2971impl std::fmt::Display for AcmCovarianceLineType {
2972 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2973 let value = match self {
2974 Self::Angle | Self::AngleLower => "ANGLE",
2975 Self::AngleGyroBias | Self::AngleGyroBiasLower => "ANGLE_GYROBIAS",
2976 Self::AngleAngVel | Self::AngleAngVelLower => "ANGLE_ANGVEL",
2977 Self::Quaternion | Self::QuaternionLower => "QUATERNION",
2978 Self::QuaternionGyroBias | Self::QuaternionGyroBiasLower => "QUATERNION_GYROBIAS",
2979 Self::QuaternionAngVel | Self::QuaternionAngVelLower => "QUATERNION_ANGVEL",
2980 };
2981 write!(f, "{}", value)
2982 }
2983}
2984
2985#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
2986pub enum AttitudeTypeType {
2987 #[serde(rename = "quaternion")]
2988 Quaternion,
2989 #[serde(rename = "QUATERNION")]
2990 QuaternionUpper,
2991 #[serde(rename = "quaternion/derivative")]
2992 QuaternionDerivative,
2993 #[serde(rename = "QUATERNION/DERIVATIVE")]
2994 QuaternionDerivativeUpper,
2995 #[serde(rename = "quaternion/angvel")]
2996 QuaternionAngVel,
2997 #[serde(rename = "QUATERNION/ANGVEL")]
2998 QuaternionAngVelUpper,
2999 #[serde(rename = "euler_angle")]
3000 EulerAngle,
3001 #[serde(rename = "EULER_ANGLE")]
3002 EulerAngleUpper,
3003 #[serde(rename = "euler_angle/derivative")]
3004 EulerAngleDerivative,
3005 #[serde(rename = "EULER_ANGLE/DERIVATIVE")]
3006 EulerAngleDerivativeUpper,
3007 #[serde(rename = "euler_angle/angvel")]
3008 EulerAngleAngVel,
3009 #[serde(rename = "EULER_ANGLE/ANGVEL")]
3010 EulerAngleAngVelUpper,
3011 #[serde(rename = "spin")]
3012 Spin,
3013 #[serde(rename = "SPIN")]
3014 SpinUpper,
3015 #[serde(rename = "spin/nutation")]
3016 SpinNutation,
3017 #[serde(rename = "SPIN/NUTATION")]
3018 SpinNutationUpper,
3019 #[serde(rename = "spin/nutation_mom")]
3020 SpinNutationMom,
3021 #[serde(rename = "SPIN/NUTATION_MOM")]
3022 SpinNutationMomUpper,
3023}
3024
3025impl std::str::FromStr for AttitudeTypeType {
3026 type Err = crate::error::EnumParseError;
3027 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3028 match s {
3029 "quaternion" => Ok(Self::Quaternion),
3030 "QUATERNION" => Ok(Self::QuaternionUpper),
3031 "quaternion/derivative" => Ok(Self::QuaternionDerivative),
3032 "QUATERNION/DERIVATIVE" => Ok(Self::QuaternionDerivativeUpper),
3033 "quaternion/angvel" => Ok(Self::QuaternionAngVel),
3034 "QUATERNION/ANGVEL" => Ok(Self::QuaternionAngVelUpper),
3035 "euler_angle" => Ok(Self::EulerAngle),
3036 "EULER_ANGLE" => Ok(Self::EulerAngleUpper),
3037 "euler_angle/derivative" => Ok(Self::EulerAngleDerivative),
3038 "EULER_ANGLE/DERIVATIVE" => Ok(Self::EulerAngleDerivativeUpper),
3039 "euler_angle/angvel" => Ok(Self::EulerAngleAngVel),
3040 "EULER_ANGLE/ANGVEL" => Ok(Self::EulerAngleAngVelUpper),
3041 "spin" => Ok(Self::Spin),
3042 "SPIN" => Ok(Self::SpinUpper),
3043 "spin/nutation" => Ok(Self::SpinNutation),
3044 "SPIN/NUTATION" => Ok(Self::SpinNutationUpper),
3045 "spin/nutation_mom" => Ok(Self::SpinNutationMom),
3046 "SPIN/NUTATION_MOM" => Ok(Self::SpinNutationMomUpper),
3047 _ => Err(crate::error::EnumParseError {
3048 field: "ATTITUDE_TYPE",
3049 value: s.to_string(),
3050 expected: "QUATERNION, QUATERNION/DERIVATIVE, QUATERNION/ANGVEL, EULER_ANGLE, EULER_ANGLE/DERIVATIVE, EULER_ANGLE/ANGVEL, SPIN, SPIN/NUTATION, or SPIN/NUTATION_MOM",
3051 }),
3052 }
3053 }
3054}
3055
3056impl std::fmt::Display for AttitudeTypeType {
3057 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3058 let value = match self {
3059 Self::Quaternion | Self::QuaternionUpper => "QUATERNION",
3060 Self::QuaternionDerivative | Self::QuaternionDerivativeUpper => "QUATERNION/DERIVATIVE",
3061 Self::QuaternionAngVel | Self::QuaternionAngVelUpper => "QUATERNION/ANGVEL",
3062 Self::EulerAngle | Self::EulerAngleUpper => "EULER_ANGLE",
3063 Self::EulerAngleDerivative | Self::EulerAngleDerivativeUpper => {
3064 "EULER_ANGLE/DERIVATIVE"
3065 }
3066 Self::EulerAngleAngVel | Self::EulerAngleAngVelUpper => "EULER_ANGLE/ANGVEL",
3067 Self::Spin | Self::SpinUpper => "SPIN",
3068 Self::SpinNutation | Self::SpinNutationUpper => "SPIN/NUTATION",
3069 Self::SpinNutationMom | Self::SpinNutationMomUpper => "SPIN/NUTATION_MOM",
3070 };
3071 write!(f, "{}", value)
3072 }
3073}
3074
3075#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3077pub enum ApmRateFrame {
3078 #[serde(rename = "EULER_FRAME_A")]
3079 EulerFrameA,
3080 #[serde(rename = "EULER_FRAME_B")]
3081 EulerFrameB,
3082}
3083
3084define_unit_enum!(SigmaUUnits, DegPerS15, { DegPerS15 => "deg/s**1.5" });
3086pub type SigmaU = UnitValue<f64, SigmaUUnits>;
3087
3088define_unit_enum!(SigmaVUnits, DegPerS05, { DegPerS05 => "deg/s**0.5" });
3089pub type SigmaV = UnitValue<f64, SigmaVUnits>;
3090
3091#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3093pub struct SensorNoise {
3094 #[serde(rename = "$value", default, with = "crate::utils::vec_f64_space_sep")]
3095 pub values: Vec<f64>,
3096 #[serde(rename = "@units", default, skip_serializing_if = "Option::is_none")]
3097 pub units: Option<AngleUnits>,
3098}
3099
3100#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3102pub enum DisintegrationType {
3103 #[serde(rename = "NONE")]
3105 None,
3106 #[serde(rename = "MASS-LOSS")]
3108 MassLoss,
3109 #[serde(rename = "BREAK-UP")]
3111 BreakUp,
3112 #[serde(rename = "MASS-LOSS + BREAK-UP", alias = "MASS-LOSS + BREAKUP")]
3114 MassLossAndBreakUp,
3115}
3116
3117impl std::str::FromStr for DisintegrationType {
3118 type Err = crate::error::EnumParseError;
3119 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3120 match s {
3121 "NONE" => Ok(Self::None),
3122 "MASS-LOSS" => Ok(Self::MassLoss),
3123 "BREAK-UP" => Ok(Self::BreakUp),
3124 "MASS-LOSS + BREAK-UP" | "MASS-LOSS + BREAKUP" => Ok(Self::MassLossAndBreakUp),
3125 _ => Err(crate::error::EnumParseError {
3126 field: "REENTRY_DISINTEGRATION",
3127 value: s.to_string(),
3128 expected: "NONE, MASS-LOSS, BREAK-UP, or MASS-LOSS + BREAK-UP",
3129 }),
3130 }
3131 }
3132}
3133
3134impl std::fmt::Display for DisintegrationType {
3135 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3136 match self {
3137 Self::None => write!(f, "NONE"),
3138 Self::MassLoss => write!(f, "MASS-LOSS"),
3139 Self::BreakUp => write!(f, "BREAK-UP"),
3140 Self::MassLossAndBreakUp => write!(f, "MASS-LOSS + BREAK-UP"),
3141 }
3142 }
3143}
3144
3145#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3147pub enum ImpactUncertaintyType {
3148 #[serde(rename = "NONE")]
3150 None,
3151 #[serde(rename = "ANALYTICAL")]
3153 Analytical,
3154 #[serde(rename = "STOCHASTIC")]
3156 Stochastic,
3157 #[serde(rename = "EMPIRICAL")]
3159 Empirical,
3160 #[serde(rename = "COVARIANCE")]
3162 Covariance,
3163 #[serde(rename = "STATISTICAL")]
3165 Statistical,
3166}
3167
3168impl std::str::FromStr for ImpactUncertaintyType {
3169 type Err = crate::error::EnumParseError;
3170 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3171 match s {
3172 "NONE" => Ok(Self::None),
3173 "ANALYTICAL" => Ok(Self::Analytical),
3174 "STOCHASTIC" => Ok(Self::Stochastic),
3175 "EMPIRICAL" => Ok(Self::Empirical),
3176 "COVARIANCE" => Ok(Self::Covariance),
3177 "STATISTICAL" => Ok(Self::Statistical),
3178 _ => Err(crate::error::EnumParseError {
3179 field: "IMPACT_UNCERTAINTY_METHOD",
3180 value: s.to_string(),
3181 expected: "NONE, ANALYTICAL, STOCHASTIC, EMPIRICAL, COVARIANCE, or STATISTICAL",
3182 }),
3183 }
3184 }
3185}
3186
3187impl std::fmt::Display for ImpactUncertaintyType {
3188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3189 match self {
3190 Self::None => write!(f, "NONE"),
3191 Self::Analytical => write!(f, "ANALYTICAL"),
3192 Self::Stochastic => write!(f, "STOCHASTIC"),
3193 Self::Empirical => write!(f, "EMPIRICAL"),
3194 Self::Covariance => write!(f, "COVARIANCE"),
3195 Self::Statistical => write!(f, "STATISTICAL"),
3196 }
3197 }
3198}
3199
3200#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3202pub enum ReentryUncertaintyMethodType {
3203 #[serde(rename = "NONE")]
3205 None,
3206 #[serde(rename = "ANALYTICAL")]
3208 Analytical,
3209 #[serde(rename = "STOCHASTIC")]
3211 Stochastic,
3212 #[serde(rename = "EMPIRICAL")]
3214 Empirical,
3215 #[serde(rename = "COVARIANCE")]
3217 Covariance,
3218 #[serde(rename = "STATISTICAL")]
3220 Statistical,
3221}
3222
3223impl std::str::FromStr for ReentryUncertaintyMethodType {
3224 type Err = crate::error::EnumParseError;
3225 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3226 match s {
3227 "NONE" => Ok(Self::None),
3228 "ANALYTICAL" => Ok(Self::Analytical),
3229 "STOCHASTIC" => Ok(Self::Stochastic),
3230 "EMPIRICAL" => Ok(Self::Empirical),
3231 "COVARIANCE" => Ok(Self::Covariance),
3232 "STATISTICAL" => Ok(Self::Statistical),
3233 _ => Err(crate::error::EnumParseError {
3234 field: "REENTRY_UNCERTAINTY_METHOD",
3235 value: s.to_string(),
3236 expected: "NONE, ANALYTICAL, STOCHASTIC, EMPIRICAL, COVARIANCE, or STATISTICAL",
3237 }),
3238 }
3239 }
3240}
3241
3242impl std::fmt::Display for ReentryUncertaintyMethodType {
3243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3244 match self {
3245 Self::None => write!(f, "NONE"),
3246 Self::Analytical => write!(f, "ANALYTICAL"),
3247 Self::Stochastic => write!(f, "STOCHASTIC"),
3248 Self::Empirical => write!(f, "EMPIRICAL"),
3249 Self::Covariance => write!(f, "COVARIANCE"),
3250 Self::Statistical => write!(f, "STATISTICAL"),
3251 }
3252 }
3253}
3254
3255#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3258pub struct TimeSystemType(pub String);
3259
3260impl std::fmt::Display for TimeSystemType {
3261 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3262 write!(f, "{}", self.0)
3263 }
3264}
3265
3266#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)]
3269pub struct AngVelFrameType(pub String);
3270
3271impl std::str::FromStr for AngVelFrameType {
3272 type Err = std::convert::Infallible;
3273 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3274 Ok(Self(s.to_string()))
3275 }
3276}
3277
3278impl std::fmt::Display for AngVelFrameType {
3279 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3280 write!(f, "{}", self.0)
3281 }
3282}
3283
3284#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Default)]
3291#[serde(rename_all = "camelCase")]
3292pub struct UserDefined {
3293 #[serde(rename = "COMMENT", default, skip_serializing_if = "Vec::is_empty")]
3297 pub comment: Vec<String>,
3298 #[serde(
3300 rename = "USER_DEFINED",
3301 default,
3302 skip_serializing_if = "Vec::is_empty"
3303 )]
3304 pub user_defined: Vec<UserDefinedParameter>,
3305}
3306
3307#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3311pub struct UserDefinedParameter {
3312 #[serde(rename = "$value", default)]
3314 pub value: String,
3315 #[serde(rename = "@parameter")]
3317 pub parameter: String,
3318}
3319
3320define_required_unit_type!(Dv, DvUnits, MPerS, { MPerS => "m/s" });
3324
3325define_required_unit_type!(M2, M2Units, M2, { M2 => "m**2" });
3327
3328define_required_unit_type!(M2s, M2sUnits, M2PerS, { M2PerS => "m**2/s" });
3330
3331define_required_unit_type!(M2s2, M2s2Units, M2PerS2, { M2PerS2 => "m**2/s**2" });
3333
3334define_required_unit_type!(M3kg, M3kgUnits, M3PerKg, { M3PerKg => "m**3/kg" });
3336
3337define_required_unit_type!(M3kgs, M3kgsUnits, M3PerKgS, { M3PerKgS => "m**3/(kg*s)" });
3339
3340define_required_unit_type!(M4kg2, M4kg2Units, M4PerKg2, { M4PerKg2 => "m**4/kg**2" });
3342
3343define_required_unit_type!(M2s3, M2s3Units, M2PerS3, { M2PerS3 => "m**2/s**3" });
3345
3346define_required_unit_type!(M3kgs2, M3kgs2Units, M3PerKgS2, { M3PerKgS2 => "m**3/(kg*s**2)" });
3348
3349define_required_unit_type!(M2s4, M2s4Units, M2PerS4, { M2PerS4 => "m**2/s**4" });
3351
3352define_unit_type!(M2kg, M2kgUnits, M2PerKg, { M2PerKg => "m**2/kg" });
3354define_required_type!(M2kgRequired, M2kgUnits, M2PerKg);
3355
3356#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3359pub enum CdmObjectType {
3360 #[serde(rename = "OBJECT1")]
3362 Object1,
3363 #[serde(rename = "OBJECT2")]
3365 Object2,
3366}
3367
3368impl std::str::FromStr for CdmObjectType {
3369 type Err = crate::error::EnumParseError;
3370 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3371 match s.to_uppercase().as_str() {
3372 "OBJECT1" => Ok(Self::Object1),
3373 "OBJECT2" => Ok(Self::Object2),
3374 _ => Err(crate::error::EnumParseError {
3375 field: "OBJECT",
3376 value: s.to_string(),
3377 expected: "OBJECT1 or OBJECT2",
3378 }),
3379 }
3380 }
3381}
3382
3383#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3385pub enum ScreenVolumeFrameType {
3386 #[serde(rename = "RTN")]
3388 Rtn,
3389 #[serde(rename = "TVN")]
3391 Tvn,
3392}
3393
3394impl std::fmt::Display for ScreenVolumeFrameType {
3395 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3396 match self {
3397 Self::Rtn => write!(f, "RTN"),
3398 Self::Tvn => write!(f, "TVN"),
3399 }
3400 }
3401}
3402
3403impl std::str::FromStr for ScreenVolumeFrameType {
3404 type Err = crate::error::EnumParseError;
3405 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3406 match s.to_uppercase().as_str() {
3407 "RTN" => Ok(Self::Rtn),
3408 "TVN" => Ok(Self::Tvn),
3409 _ => Err(crate::error::EnumParseError {
3410 field: "SCREEN_VOLUME_FRAME",
3411 value: s.to_string(),
3412 expected: "RTN or TVN",
3413 }),
3414 }
3415 }
3416}
3417
3418#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3420pub enum ScreenVolumeShapeType {
3421 #[serde(rename = "ELLIPSOID")]
3423 Ellipsoid,
3424 #[serde(rename = "BOX")]
3426 Box,
3427}
3428
3429impl std::fmt::Display for ScreenVolumeShapeType {
3430 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3431 match self {
3432 Self::Ellipsoid => write!(f, "ELLIPSOID"),
3433 Self::Box => write!(f, "BOX"),
3434 }
3435 }
3436}
3437
3438impl std::str::FromStr for ScreenVolumeShapeType {
3439 type Err = crate::error::EnumParseError;
3440 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3441 match s.to_uppercase().as_str() {
3442 "ELLIPSOID" => Ok(Self::Ellipsoid),
3443 "BOX" => Ok(Self::Box),
3444 _ => Err(crate::error::EnumParseError {
3445 field: "SCREEN_VOLUME_SHAPE",
3446 value: s.to_string(),
3447 expected: "ELLIPSOID or BOX",
3448 }),
3449 }
3450 }
3451}
3452
3453#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3455pub enum ReferenceFrameType {
3456 #[serde(rename = "GCRF")]
3458 Gcrf,
3459 #[serde(rename = "EME2000")]
3461 Eme2000,
3462 #[serde(rename = "ITRF")]
3464 Itrf,
3465}
3466
3467impl std::fmt::Display for ReferenceFrameType {
3468 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3469 match self {
3470 Self::Gcrf => write!(f, "GCRF"),
3471 Self::Eme2000 => write!(f, "EME2000"),
3472 Self::Itrf => write!(f, "ITRF"),
3473 }
3474 }
3475}
3476
3477impl std::str::FromStr for ReferenceFrameType {
3478 type Err = crate::error::EnumParseError;
3479 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3480 match s.to_uppercase().as_str() {
3481 "GCRF" => Ok(Self::Gcrf),
3482 "EME2000" => Ok(Self::Eme2000),
3483 "ITRF" => Ok(Self::Itrf),
3484 _ => Err(crate::error::EnumParseError {
3485 field: "REF_FRAME",
3486 value: s.to_string(),
3487 expected: "GCRF, EME2000, or ITRF",
3488 }),
3489 }
3490 }
3491}
3492
3493#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3495pub enum CovarianceMethodType {
3496 #[serde(rename = "CALCULATED")]
3498 Calculated,
3499 #[serde(rename = "DEFAULT")]
3501 Default,
3502}
3503
3504impl std::fmt::Display for CovarianceMethodType {
3505 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3506 match self {
3507 Self::Calculated => write!(f, "CALCULATED"),
3508 Self::Default => write!(f, "DEFAULT"),
3509 }
3510 }
3511}
3512
3513impl std::str::FromStr for CovarianceMethodType {
3514 type Err = crate::error::EnumParseError;
3515 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3516 match s.to_uppercase().as_str() {
3517 "CALCULATED" => Ok(Self::Calculated),
3518 "DEFAULT" => Ok(Self::Default),
3519 _ => Err(crate::error::EnumParseError {
3520 field: "COVARIANCE_METHOD",
3521 value: s.to_string(),
3522 expected: "CALCULATED or DEFAULT",
3523 }),
3524 }
3525 }
3526}
3527
3528#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3530pub enum ManeuverableType {
3531 #[serde(rename = "YES")]
3533 Yes,
3534 #[serde(rename = "NO")]
3536 No,
3537 #[serde(rename = "N/A")]
3539 NA,
3540}
3541
3542impl std::fmt::Display for ManeuverableType {
3543 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3544 match self {
3545 Self::Yes => write!(f, "YES"),
3546 Self::No => write!(f, "NO"),
3547 Self::NA => write!(f, "N/A"),
3548 }
3549 }
3550}
3551
3552impl std::str::FromStr for ManeuverableType {
3553 type Err = crate::error::EnumParseError;
3554 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3555 match s.to_uppercase().as_str() {
3556 "YES" => Ok(Self::Yes),
3557 "NO" => Ok(Self::No),
3558 "N/A" => Ok(Self::NA),
3559 _ => Err(crate::error::EnumParseError {
3560 field: "MANEUVERABLE",
3561 value: s.to_string(),
3562 expected: "YES, NO, or N/A",
3563 }),
3564 }
3565 }
3566}
3567
3568#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3574pub struct Vec3Double {
3575 pub x: f64,
3576 pub y: f64,
3577 pub z: f64,
3578}
3579
3580impl Vec3Double {
3581 pub fn new(x: f64, y: f64, z: f64) -> Self {
3582 Self { x, y, z }
3583 }
3584}
3585
3586impl FromKvnValue for Vec3Double {
3587 fn from_kvn_value(val: &str) -> Result<Self> {
3588 let parts: Vec<&str> = val.split_whitespace().collect();
3589 if parts.len() != 3 {
3590 return Err(crate::error::FormatError::InvalidFormat(format!(
3591 "Vec3Double requires 3 values, got {}: {}",
3592 parts.len(),
3593 val
3594 ))
3595 .into());
3596 }
3597 let x = fast_float::parse(parts[0]).map_err(|_| {
3598 CcsdsNdmError::Validation(Box::new(crate::error::ValidationError::Generic {
3599 message: "Invalid X component".into(),
3600 line: None,
3601 }))
3602 })?;
3603 let y = fast_float::parse(parts[1]).map_err(|_| {
3604 CcsdsNdmError::Validation(Box::new(crate::error::ValidationError::Generic {
3605 message: "Invalid Y component".into(),
3606 line: None,
3607 }))
3608 })?;
3609 let z = fast_float::parse(parts[2]).map_err(|_| {
3610 CcsdsNdmError::Validation(Box::new(crate::error::ValidationError::Generic {
3611 message: "Invalid Z component".into(),
3612 line: None,
3613 }))
3614 })?;
3615 Ok(Self { x, y, z })
3616 }
3617}
3618
3619impl std::fmt::Display for Vec3Double {
3620 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3621 write!(f, "{} {} {}", self.x, self.y, self.z)
3622 }
3623}
3624
3625#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3627pub struct Vec4Double {
3628 #[serde(rename = "$value", with = "crate::utils::vec_f64_space_sep")]
3629 pub values: Vec<f64>,
3630}
3631
3632impl Vec4Double {
3633 pub fn new(a: f64, b: f64, c: f64, d: f64) -> Self {
3634 Self {
3635 values: vec![a, b, c, d],
3636 }
3637 }
3638}
3639
3640impl FromKvnValue for Vec4Double {
3641 fn from_kvn_value(val: &str) -> Result<Self> {
3642 let parts: Vec<&str> = val.split_whitespace().collect();
3643 if parts.len() != 4 {
3644 return Err(crate::error::FormatError::InvalidFormat(format!(
3645 "Vec4Double requires 4 values, got {}: {}",
3646 parts.len(),
3647 val
3648 ))
3649 .into());
3650 }
3651 let mut values = Vec::with_capacity(4);
3652 for p in parts {
3653 let v = fast_float::parse(p).map_err(|_| {
3654 crate::error::FormatError::InvalidFormat(format!(
3655 "Vec4Double value parse failed: {}",
3656 p
3657 ))
3658 })?;
3659 values.push(v);
3660 }
3661 Ok(Self { values })
3662 }
3663}
3664
3665impl std::fmt::Display for Vec4Double {
3666 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3667 let mut iter = self.values.iter();
3668 if let Some(first) = iter.next() {
3669 write!(f, "{}", first)?;
3670 }
3671 for v in iter {
3672 write!(f, " {}", v)?;
3673 }
3674 Ok(())
3675 }
3676}
3677
3678#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3682pub enum TdmAngleType {
3683 #[serde(rename = "AZEL")]
3685 Azel,
3686 #[serde(rename = "RADEC")]
3689 Radec,
3690 #[serde(rename = "XEYN")]
3692 Xeyn,
3693 #[serde(rename = "XSYE")]
3695 Xsye,
3696}
3697
3698impl std::str::FromStr for TdmAngleType {
3699 type Err = crate::error::EnumParseError;
3700 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3701 match s.to_uppercase().as_str() {
3702 "AZEL" => Ok(Self::Azel),
3703 "RADEC" => Ok(Self::Radec),
3704 "XEYN" => Ok(Self::Xeyn),
3705 "XSYE" => Ok(Self::Xsye),
3706 _ => Err(crate::error::EnumParseError {
3707 field: "ANGLE_TYPE",
3708 value: s.to_string(),
3709 expected: "AZEL, RADEC, XEYN, or XSYE",
3710 }),
3711 }
3712 }
3713}
3714
3715impl std::fmt::Display for TdmAngleType {
3716 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3717 match self {
3718 Self::Azel => write!(f, "AZEL"),
3719 Self::Radec => write!(f, "RADEC"),
3720 Self::Xeyn => write!(f, "XEYN"),
3721 Self::Xsye => write!(f, "XSYE"),
3722 }
3723 }
3724}
3725
3726#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3728pub enum TdmDataQuality {
3729 #[serde(rename = "RAW")]
3731 Raw,
3732 #[serde(rename = "VALIDATED")]
3734 Validated,
3735 #[serde(rename = "DEGRADED")]
3737 Degraded,
3738}
3739
3740impl std::str::FromStr for TdmDataQuality {
3741 type Err = crate::error::EnumParseError;
3742 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3743 match s.to_uppercase().as_str() {
3744 "RAW" => Ok(Self::Raw),
3745 "VALIDATED" => Ok(Self::Validated),
3746 "DEGRADED" => Ok(Self::Degraded),
3747 _ => Err(crate::error::EnumParseError {
3748 field: "DATA_QUALITY",
3749 value: s.to_string(),
3750 expected: "RAW, VALIDATED, or DEGRADED",
3751 }),
3752 }
3753 }
3754}
3755
3756impl std::fmt::Display for TdmDataQuality {
3757 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3758 match self {
3759 Self::Raw => write!(f, "RAW"),
3760 Self::Validated => write!(f, "VALIDATED"),
3761 Self::Degraded => write!(f, "DEGRADED"),
3762 }
3763 }
3764}
3765
3766#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3768pub enum TdmIntegrationRef {
3769 #[serde(rename = "START")]
3771 Start,
3772 #[serde(rename = "MIDDLE")]
3774 Middle,
3775 #[serde(rename = "END")]
3777 End,
3778}
3779
3780impl std::str::FromStr for TdmIntegrationRef {
3781 type Err = crate::error::EnumParseError;
3782 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3783 match s.to_uppercase().as_str() {
3784 "START" => Ok(Self::Start),
3785 "MIDDLE" => Ok(Self::Middle),
3786 "END" => Ok(Self::End),
3787 _ => Err(crate::error::EnumParseError {
3788 field: "INTEGRATION_REF",
3789 value: s.to_string(),
3790 expected: "START, MIDDLE, or END",
3791 }),
3792 }
3793 }
3794}
3795
3796impl std::fmt::Display for TdmIntegrationRef {
3797 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3798 match self {
3799 Self::Start => write!(f, "START"),
3800 Self::Middle => write!(f, "MIDDLE"),
3801 Self::End => write!(f, "END"),
3802 }
3803 }
3804}
3805
3806#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3808pub enum TdmMode {
3809 #[serde(rename = "SEQUENTIAL")]
3814 Sequential,
3815 #[serde(rename = "SINGLE_DIFF")]
3817 SingleDiff,
3818}
3819
3820impl std::str::FromStr for TdmMode {
3821 type Err = crate::error::EnumParseError;
3822 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3823 match s.to_uppercase().as_str() {
3824 "SEQUENTIAL" => Ok(Self::Sequential),
3825 "SINGLE_DIFF" => Ok(Self::SingleDiff),
3826 _ => Err(crate::error::EnumParseError {
3827 field: "MODE",
3828 value: s.to_string(),
3829 expected: "SEQUENTIAL or SINGLE_DIFF",
3830 }),
3831 }
3832 }
3833}
3834
3835impl std::fmt::Display for TdmMode {
3836 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3837 match self {
3838 Self::Sequential => write!(f, "SEQUENTIAL"),
3839 Self::SingleDiff => write!(f, "SINGLE_DIFF"),
3840 }
3841 }
3842}
3843
3844#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3846pub enum TdmRangeMode {
3847 #[serde(rename = "COHERENT")]
3849 Coherent,
3850 #[serde(rename = "CONSTANT")]
3852 Constant,
3853 #[serde(rename = "ONE_WAY")]
3855 OneWay,
3856}
3857
3858impl std::str::FromStr for TdmRangeMode {
3859 type Err = crate::error::EnumParseError;
3860 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3861 match s.to_uppercase().as_str() {
3862 "COHERENT" => Ok(Self::Coherent),
3863 "CONSTANT" => Ok(Self::Constant),
3864 "ONE_WAY" => Ok(Self::OneWay),
3865 _ => Err(crate::error::EnumParseError {
3866 field: "RANGE_MODE",
3867 value: s.to_string(),
3868 expected: "COHERENT, CONSTANT, or ONE_WAY",
3869 }),
3870 }
3871 }
3872}
3873
3874impl std::fmt::Display for TdmRangeMode {
3875 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3876 match self {
3877 Self::Coherent => write!(f, "COHERENT"),
3878 Self::Constant => write!(f, "CONSTANT"),
3879 Self::OneWay => write!(f, "ONE_WAY"),
3880 }
3881 }
3882}
3883
3884#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3886pub enum TdmRangeUnits {
3887 #[serde(rename = "km")]
3889 Km,
3890 #[serde(rename = "s")]
3892 Seconds,
3893 #[serde(rename = "RU")]
3895 Ru,
3896}
3897
3898impl std::str::FromStr for TdmRangeUnits {
3899 type Err = crate::error::EnumParseError;
3900 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3901 match s.to_lowercase().as_str() {
3902 "km" => Ok(Self::Km),
3903 "s" => Ok(Self::Seconds),
3904 "ru" => Ok(Self::Ru),
3905 _ => Err(crate::error::EnumParseError {
3906 field: "RANGE_UNITS",
3907 value: s.to_string(),
3908 expected: "km, s, or ru",
3909 }),
3910 }
3911 }
3912}
3913
3914impl std::fmt::Display for TdmRangeUnits {
3915 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3916 match self {
3917 Self::Km => write!(f, "km"),
3918 Self::Seconds => write!(f, "s"),
3919 Self::Ru => write!(f, "ru"),
3920 }
3921 }
3922}
3923
3924#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3925pub enum TdmReferenceFrame {
3926 #[serde(rename = "EME2000")]
3927 Eme2000,
3928 #[serde(rename = "ICRF")]
3929 Icrf,
3930 #[serde(rename = "ITRF2000")]
3931 Itrf2000,
3932 #[serde(rename = "ITRF-93")]
3933 Itrf93,
3934 #[serde(rename = "ITRF-97")]
3935 Itrf97,
3936 #[serde(rename = "TOD")]
3937 Tod,
3938}
3939
3940impl std::str::FromStr for TdmReferenceFrame {
3941 type Err = crate::error::EnumParseError;
3942 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3943 match s.to_uppercase().as_str() {
3944 "EME2000" => Ok(Self::Eme2000),
3945 "ICRF" => Ok(Self::Icrf),
3946 "ITRF2000" | "ITRF-2000" => Ok(Self::Itrf2000),
3947 "ITRF-93" | "ITRF1993" | "ITRF93" => Ok(Self::Itrf93),
3948 "ITRF-97" => Ok(Self::Itrf97),
3949 "TOD" | "TOD_EARTH" => Ok(Self::Tod),
3950 _ => Err(crate::error::EnumParseError {
3951 field: "REFERENCE_FRAME",
3952 value: s.to_string(),
3953 expected: "EME2000, ICRF, ITRF2000, ITRF-93, ITRF-97, or TOD",
3954 }),
3955 }
3956 }
3957}
3958
3959impl std::fmt::Display for TdmReferenceFrame {
3960 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
3961 match self {
3962 Self::Eme2000 => write!(f, "EME2000"),
3963 Self::Icrf => write!(f, "ICRF"),
3964 Self::Itrf2000 => write!(f, "ITRF2000"),
3965 Self::Itrf93 => write!(f, "ITRF-93"),
3966 Self::Itrf97 => write!(f, "ITRF-97"),
3967 Self::Tod => write!(f, "TOD"),
3968 }
3969 }
3970}
3971
3972#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
3974pub enum TdmTimetagRef {
3975 #[serde(rename = "TRANSMIT")]
3977 Transmit,
3978 #[serde(rename = "RECEIVE")]
3980 Receive,
3981}
3982
3983impl std::str::FromStr for TdmTimetagRef {
3984 type Err = crate::error::EnumParseError;
3985 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
3986 match s.to_uppercase().as_str() {
3987 "TRANSMIT" => Ok(Self::Transmit),
3988 "RECEIVE" => Ok(Self::Receive),
3989 _ => Err(crate::error::EnumParseError {
3990 field: "TIMETAG_REF",
3991 value: s.to_string(),
3992 expected: "TRANSMIT or RECEIVE",
3993 }),
3994 }
3995 }
3996}
3997
3998impl std::fmt::Display for TdmTimetagRef {
3999 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4000 match self {
4001 Self::Transmit => write!(f, "TRANSMIT"),
4002 Self::Receive => write!(f, "RECEIVE"),
4003 }
4004 }
4005}
4006
4007#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
4009#[serde(transparent)]
4010pub struct TdmPath(pub String);
4011
4012impl std::str::FromStr for TdmPath {
4013 type Err = crate::error::ValidationError;
4014 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
4015 let parts: Vec<&str> = s.split(',').collect();
4017 if parts.len() < 2 {
4018 return Err(crate::error::ValidationError::InvalidValue {
4019 field: "PATH".into(),
4020 value: s.to_string(),
4021 expected: "at least two participants (e.g., 1,2)".into(),
4022 line: None,
4023 });
4024 }
4025 for part in &parts {
4026 if part.len() != 1 || !part.chars().next().unwrap().is_ascii_digit() {
4027 return Err(crate::error::ValidationError::InvalidValue {
4028 field: "PATH".into(),
4029 value: s.to_string(),
4030 expected: "single digit participant indices separated by commas".into(),
4031 line: None,
4032 });
4033 }
4034 let idx = part.parse::<u8>().unwrap();
4035 if !(1..=5).contains(&idx) {
4036 return Err(crate::error::ValidationError::InvalidValue {
4037 field: "PATH".into(),
4038 value: s.to_string(),
4039 expected: "participant indices in range 1..5".into(),
4040 line: None,
4041 });
4042 }
4043 }
4044 Ok(Self(s.to_string()))
4045 }
4046}
4047
4048impl std::fmt::Display for TdmPath {
4049 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4050 write!(f, "{}", self.0)
4051 }
4052}
4053
4054#[cfg(test)]
4055mod tests {
4056 use super::*;
4057
4058 #[test]
4059 fn test_non_negative_double() {
4060 assert!(NonNegativeDouble::new(0.0).is_ok());
4061 assert!(NonNegativeDouble::new(1.0).is_ok());
4062 assert!(NonNegativeDouble::new(-0.1).is_err());
4063 }
4064
4065 #[test]
4066 fn test_positive_integer() {
4067 assert!(PositiveInteger::new(1).is_ok());
4068 assert!(PositiveInteger::new(100).is_ok());
4069 assert!(PositiveInteger::new(0).is_err());
4070 }
4071
4072 #[test]
4073 fn test_element_set_no() {
4074 assert!(ElementSetNo::new(0).is_ok());
4075 assert!(ElementSetNo::new(9999).is_ok());
4076 assert!(ElementSetNo::new(10000).is_err());
4077 }
4078
4079 #[test]
4080 fn test_epoch_xsd_compliance() {
4081 assert!(Epoch::new("2023-11-13T12:00:00").is_ok());
4083 assert!(Epoch::new("2023-11-13T12:00:00Z").is_ok());
4084 assert!(Epoch::new("2023-11-13T12:00:00.123Z").is_ok());
4085 assert!(Epoch::new("2023-317T12:00:00Z").is_ok()); assert!(Epoch::new("2023-11-13T12:00:00+05:00").is_ok());
4087 assert!(Epoch::new("2023-11-13T12:00:00-05:00").is_ok());
4088 assert!(Epoch::new("-2023-11-13T12:00:00Z").is_ok()); assert!(Epoch::new("12345.678").is_ok());
4092 assert!(Epoch::new("+12345.678").is_ok());
4093 assert!(Epoch::new("-12345.678").is_ok());
4094 assert!(Epoch::new(".678").is_ok());
4095 assert!(Epoch::new("12345.").is_ok());
4096 assert!(Epoch::new("12345").is_ok());
4097 assert!(Epoch::new("+").is_ok()); assert!(Epoch::new("-").is_ok()); assert!(Epoch::new(".").is_ok()); assert!(Epoch::new("").is_ok());
4103
4104 assert!(Epoch::new("2023-11-13").is_err()); assert!(Epoch::new("2023-11-13T12:00").is_err()); assert!(Epoch::new("2023-11-13T12:00:00Z+05:00").is_err()); assert!(Epoch::new("not-a-date").is_err());
4109 }
4110
4111 #[test]
4112 fn test_epoch_length_limit() {
4113 let long_epoch = "A".repeat(65);
4114 assert!(Epoch::new(&long_epoch).is_err());
4115 let _max_epoch = "A".repeat(64);
4116 let long_numeric = "1".repeat(64);
4119 assert!(Epoch::new(&long_numeric).is_ok());
4120 let too_long_numeric = "1".repeat(65);
4121 assert!(Epoch::new(&too_long_numeric).is_err());
4122 }
4123}
4124
4125#[cfg(test)]
4126mod extra_tests {
4127 use super::*;
4128 use std::str::FromStr;
4129
4130 #[test]
4131 fn test_vec3double_from_kvn_error() {
4132 assert!(Vec3Double::from_kvn_value("1.0 2.0").is_err()); assert!(Vec3Double::from_kvn_value("1.0 2.0 3.0 4.0").is_err()); assert!(Vec3Double::from_kvn_value("1.0 foo 3.0").is_err()); assert!(Vec3Double::from_kvn_value("invalid").is_err());
4136 }
4137
4138 #[test]
4139 fn test_vec3double_display() {
4140 let v = Vec3Double::new(1.1, 2.2, 3.3);
4141 assert_eq!(format!("{}", v), "1.1 2.2 3.3");
4142 }
4143
4144 macro_rules! test_enum_from_str {
4145 ($type:ty, $valid:expr, $invalid:expr) => {
4146 assert!($valid.parse::<$type>().is_ok());
4148 let res = $invalid.parse::<$type>();
4150 assert!(res.is_err());
4151 let err = res.unwrap_err();
4153 assert!(!err.to_string().is_empty());
4154 };
4155 }
4156
4157 #[test]
4158 fn test_enum_parsing_errors() {
4159 test_enum_from_str!(ReentryUncertaintyMethodType, "NONE", "INVALID");
4160 test_enum_from_str!(CdmObjectType, "OBJECT1", "INVALID");
4161 test_enum_from_str!(ScreenVolumeFrameType, "RTN", "INVALID");
4162 test_enum_from_str!(ScreenVolumeShapeType, "BOX", "INVALID");
4163 test_enum_from_str!(ReferenceFrameType, "GCRF", "INVALID");
4164 test_enum_from_str!(CovarianceMethodType, "CALCULATED", "INVALID");
4165 test_enum_from_str!(ManeuverableType, "YES", "INVALID");
4166 test_enum_from_str!(TdmAngleType, "AZEL", "INVALID");
4167 test_enum_from_str!(TdmDataQuality, "RAW", "INVALID");
4168 test_enum_from_str!(TdmIntegrationRef, "START", "INVALID");
4169 test_enum_from_str!(TdmMode, "SEQUENTIAL", "INVALID");
4170 test_enum_from_str!(TdmRangeMode, "COHERENT", "INVALID");
4171 test_enum_from_str!(TdmRangeUnits, "km", "INVALID");
4172 test_enum_from_str!(TdmReferenceFrame, "EME2000", "INVALID");
4173 test_enum_from_str!(TdmTimetagRef, "TRANSMIT", "INVALID");
4174 }
4175
4176 #[test]
4177 fn test_unit_value_from_kvn() {
4178 let uv = UnitValue::<f64, PositionUnits>::from_kvn("123.45", Some("km")).unwrap();
4179 assert_eq!(uv.value, 123.45);
4180 assert_eq!(uv.units, Some(PositionUnits::Km));
4181
4182 let uv_no_unit = UnitValue::<f64, PositionUnits>::from_kvn("123.45", None).unwrap();
4183 assert_eq!(uv_no_unit.units, None);
4184 }
4185
4186 #[test]
4187 fn test_angle_validation() {
4188 assert!(Angle::new(359.9, None).is_ok());
4189 assert!(Angle::new(-359.9, None).is_ok());
4190 assert!(Angle::new(360.0, None).is_err());
4191 assert!(Angle::new(-360.1, None).is_err());
4192 }
4193
4194 #[test]
4195 fn test_day_interval_validation() {
4196 assert!(DayInterval::new(10.0, None).is_ok());
4197 assert!(DayInterval::new(-0.1, None).is_err());
4198 assert!(DayIntervalRequired::new(0.1).is_ok());
4199 assert!(DayIntervalRequired::new(0.0).is_err());
4200 }
4201
4202 #[test]
4203 fn test_frequency_validation() {
4204 assert!(Frequency::new(1.0, None).is_ok());
4205 assert!(Frequency::new(0.0, None).is_err());
4206 }
4207
4208 #[test]
4209 fn test_gm_validation() {
4210 assert!(Gm::new(1.0, None).is_ok());
4211 assert!(Gm::new(0.0, None).is_err());
4212 assert!("KM**3/S**2".parse::<GmUnits>().is_ok());
4213 }
4214
4215 #[test]
4216 fn test_altitude_required_validation() {
4217 assert!(AltitudeRequired::new(0.0).is_ok());
4218 assert!(AltitudeRequired::new(9000.0).is_err());
4219 assert!(AltitudeRequired::new(-431.0).is_err());
4220 }
4221
4222 #[test]
4223 fn test_mass_validation() {
4224 assert!(Mass::new(0.0, None).is_ok());
4225 assert!(Mass::new(-1.0, None).is_err());
4226 }
4227
4228 #[test]
4229 fn test_area_validation() {
4230 assert!(Area::new(0.0, None).is_ok());
4231 assert!(Area::new(-1.0, None).is_err());
4232 }
4233
4234 #[test]
4235 fn test_ms2_parsing() {
4236 let ms2 = Ms2::from_str("9.81").unwrap();
4237 assert_eq!(ms2.value, 9.81);
4238 assert_eq!(ms2.units, Ms2Units::MPerS2);
4239 }
4240
4241 #[test]
4242 fn test_solar_flux_units() {
4243 test_enum_from_str!(SolarFluxUnits, "SFU", "INVALID");
4244 assert_eq!(format!("{}", SolarFluxUnits::JanskyScaled), "10**4 Jansky");
4245 }
4246
4247 #[test]
4248 fn test_epoch_conversion() {
4249 let s = "2023-01-01T00:00:00Z";
4250 let e = Epoch::from_str(s).unwrap();
4251 assert_eq!(Epoch::try_from(s.to_string()).unwrap(), e);
4252 assert_eq!(e.as_str(), s);
4253 assert!(!e.is_empty());
4254 }
4255
4256 #[test]
4257 fn test_percentage_validation() {
4258 assert!(Percentage::new(50.0, None).is_ok());
4259 assert!(Percentage::new(-0.1, None).is_err());
4260 assert!(Percentage::new(100.1, None).is_err());
4261 assert!(PercentageRequired::new(50.0).is_ok());
4262 assert!(PercentageRequired::new(-0.1).is_err());
4263 assert!(PercentageRequired::new(100.1).is_err());
4264 }
4265
4266 #[test]
4267 fn test_unit_conversions() {
4268 let f = Frequency::new(10.0, Some(FrequencyUnits::Hz)).unwrap();
4269 let uv = f.to_unit_value();
4270 assert_eq!(uv.value, 10.0);
4271 assert_eq!(uv.units, Some(FrequencyUnits::Hz));
4272
4273 let gm = Gm::new(1.0, Some(GmUnits::Km3PerS2)).unwrap();
4274 let uv = gm.to_unit_value();
4275 assert_eq!(uv.value, 1.0);
4276 assert_eq!(uv.units, Some(GmUnits::Km3PerS2));
4277
4278 let a = Angle::new(1.0, Some(AngleUnits::Deg)).unwrap();
4279 let uv = a.to_unit_value();
4280 assert_eq!(uv.value, 1.0);
4281 assert_eq!(uv.units, Some(AngleUnits::Deg));
4282 }
4283
4284 #[test]
4285 fn test_from_kvn_float() {
4286 let f = Frequency::from_kvn_float(10.0, Some("Hz")).unwrap();
4287 assert_eq!(f.value, 10.0);
4288 assert_eq!(f.units, Some(FrequencyUnits::Hz));
4289
4290 let gm = Gm::from_kvn_float(1.0, Some("KM**3/S**2")).unwrap();
4291 assert_eq!(gm.value, 1.0);
4292 }
4293
4294 #[test]
4295 fn test_additional_units() {
4296 test_enum_from_str!(AngleRateUnits, "deg/s", "INVALID");
4297 test_enum_from_str!(MomentUnits, "kg*m**2", "INVALID");
4298 test_enum_from_str!(QuaternionDotUnits, "1/s", "INVALID");
4299 }
4300
4301 #[test]
4302 fn test_tdm_reference_frame_aliases() {
4303 assert!("ITRF1993".parse::<TdmReferenceFrame>().is_ok());
4304 assert!("ITRF93".parse::<TdmReferenceFrame>().is_ok());
4305 assert!("TOD_EARTH".parse::<TdmReferenceFrame>().is_ok());
4306 }
4307
4308 #[test]
4309 fn test_tdm_path_index_range_validation() {
4310 assert!("1,2,1".parse::<TdmPath>().is_ok());
4311 assert!("1,6".parse::<TdmPath>().is_err());
4312 assert!("0,2".parse::<TdmPath>().is_err());
4313 }
4314}