use crate::frame_descriptor::{FrameClass, FrameRole, FrameUid, Namespace, Tag};
pub const MISSION_NAMED_NS: Namespace = Namespace(1);
pub fn named_body_frame_uid(name: &str) -> FrameUid {
FrameUid::external(
MISSION_NAMED_NS,
FrameClass::Body,
FrameRole::CompositeBody,
Tag::Named(name.into()),
)
}
pub fn topocentric_site_frame_uid(planet: &str, site_key: &str) -> FrameUid {
FrameUid::external(
MISSION_NAMED_NS,
FrameClass::Topocentric,
FrameRole::Primary,
Tag::Named(format!("{planet}/site:{site_key}").into()),
)
}
pub fn pfix_sibling_uid(inertial: &FrameUid) -> FrameUid {
assert!(
inertial.class == FrameClass::PlanetInertial,
"pfix_sibling_uid: identity `{inertial}` has class {:?}, not \
PlanetInertial — only a planet's inertial-frame identity has a \
planet-fixed sibling.",
inertial.class
);
FrameUid {
namespace: inertial.namespace,
class: FrameClass::PlanetFixed,
role: inertial.role.clone(),
tag: inertial.tag.clone(),
}
}
pub fn sealed_planet_inertial_uid(name: &str) -> Option<FrameUid> {
use crate::frame::{Earth, Jupiter, Mars, Moon, PlanetInertial, Saturn, Sun};
Some(match name {
"Earth" => FrameUid::of::<PlanetInertial<Earth>>(),
"Moon" => FrameUid::of::<PlanetInertial<Moon>>(),
"Sun" => FrameUid::of::<PlanetInertial<Sun>>(),
"Mars" => FrameUid::of::<PlanetInertial<Mars>>(),
"Jupiter" => FrameUid::of::<PlanetInertial<Jupiter>>(),
"Saturn" => FrameUid::of::<PlanetInertial<Saturn>>(),
_ => return None,
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::frame::BodyFrame;
use crate::frame_descriptor::FrameUid;
crate::define_vehicle!(IdentityTestVehicle);
#[test]
fn named_identity_never_aliases_typed_identity() {
let named = named_body_frame_uid("IdentityTestVehicle");
let typed = FrameUid::of::<BodyFrame<IdentityTestVehicle>>();
assert_ne!(named, typed);
assert_eq!(named.namespace, MISSION_NAMED_NS);
assert!(!named.is::<BodyFrame<IdentityTestVehicle>>());
}
#[test]
fn pfix_sibling_matches_typed_mint_for_every_sealed_planet() {
use crate::frame::{Earth, Jupiter, Mars, Moon, PlanetFixed, PlanetInertial, Saturn, Sun};
macro_rules! check {
($($p:ty),+) => {$(
assert_eq!(
pfix_sibling_uid(&FrameUid::of::<PlanetInertial<$p>>()),
FrameUid::of::<PlanetFixed<$p>>(),
"pfix sibling derivation must equal the typed mint",
);
)+};
}
check!(Earth, Moon, Sun, Mars, Jupiter, Saturn);
}
#[test]
#[should_panic(expected = "not PlanetInertial")]
fn pfix_sibling_rejects_non_inertial_input() {
let _ = pfix_sibling_uid(&named_body_frame_uid("iss"));
}
#[test]
fn sealed_planet_dispatch_matches_typed_mint() {
use crate::frame::{Earth, Jupiter, Mars, Moon, PlanetInertial, Saturn, Sun};
macro_rules! check {
($($p:ty),+) => {$(
assert_eq!(
sealed_planet_inertial_uid(<$p as crate::frame::Planet>::NAME),
Some(FrameUid::of::<PlanetInertial<$p>>()),
"name dispatch must equal the typed mint",
);
)+};
}
check!(Earth, Moon, Sun, Mars, Jupiter, Saturn);
assert_eq!(sealed_planet_inertial_uid("Pluto"), None);
assert_eq!(sealed_planet_inertial_uid("earth"), None, "case-sensitive");
}
#[test]
fn named_identities_are_name_keyed() {
assert_eq!(named_body_frame_uid("iss"), named_body_frame_uid("iss"));
assert_ne!(named_body_frame_uid("iss"), named_body_frame_uid("soyuz"));
assert_eq!(
named_body_frame_uid("iss").to_string(),
"ns1:iss.composite_body"
);
}
#[test]
fn topocentric_site_identities_are_key_keyed() {
assert_eq!(
topocentric_site_frame_uid("Earth", "KSC-LC39A"),
topocentric_site_frame_uid("Earth", "KSC-LC39A"),
);
assert_ne!(
topocentric_site_frame_uid("Earth", "KSC-LC39A"),
topocentric_site_frame_uid("Earth", "Baikonur-1-5"),
);
assert_ne!(
topocentric_site_frame_uid("Earth", "Base-Alpha"),
topocentric_site_frame_uid("Moon", "Base-Alpha"),
);
}
#[test]
fn topocentric_site_uid_format_is_stable() {
let uid = topocentric_site_frame_uid("Earth", "KSC-LC39A");
assert_eq!(uid.namespace, MISSION_NAMED_NS);
assert_eq!(uid.class, FrameClass::Topocentric);
assert_eq!(uid.role, FrameRole::Primary);
assert_eq!(uid.tag, Tag::Named("Earth/site:KSC-LC39A".into()));
assert_eq!(uid.to_string(), "ns1:Earth/site:KSC-LC39A.topo");
}
#[test]
fn topocentric_site_never_aliases_named_body() {
let site = topocentric_site_frame_uid("Earth", "iss");
let body = named_body_frame_uid("iss");
assert_ne!(site, body);
assert_eq!(site.namespace, body.namespace, "same namespace…");
assert_ne!(site.class, body.class, "…disjoint by class");
assert_ne!(site.role, body.role, "…and by role");
}
}