geometry_tag/same_as.rs
1//! Type equality expressible as a trait bound.
2//!
3//! Strategy impls in later crates need to constrain *"both inputs share a
4//! coordinate-system family"*, which is `std::is_same<X, Y>` in C++
5//! (`boost/geometry/core/cs.hpp` and the strategy `services` headers use
6//! this pattern extensively). Rust's generics do not let you write `where
7//! X = Y` directly, so we encode the same idea as `where X: SameAs<Y>`. The
8//! `sealed` super-trait ensures only the reflexive impl can exist
9//! downstream.
10
11mod sealed {
12 /// Sealed super-trait — only this crate may implement it, which is
13 /// what makes `SameAs<T>` actually mean equality.
14 pub trait Sealed<T> {}
15}
16
17/// `T: SameAs<U>` holds iff `T` and `U` are the same type.
18///
19/// Conceptually the trait-bound form of `std::is_same<X, Y>`, used by
20/// strategy bounds to require that two generic parameters share a
21/// coordinate-system family. Compare with the equality checks performed
22/// inside `boost/geometry/strategies/distance/services.hpp` when selecting
23/// a default strategy.
24///
25/// # Compile-time diagnostic
26///
27/// In practice the only way a downstream caller fails this bound is by
28/// pairing a non-Cartesian point with a Cartesian-only strategy like
29/// `Pythagoras` (the silent-Cartesian trap from proposal §8). The
30/// `#[diagnostic::on_unimplemented]` plate below redirects that error
31/// to the matching mitigation — see
32/// [`WithCs`](../../geometry_adapt/struct.WithCs.html) and T31.
33///
34/// # Examples
35///
36/// ```
37/// use geometry_tag::SameAs;
38/// fn require_same<T: SameAs<U>, U>() {}
39/// require_same::<u32, u32>(); // T == U: holds
40/// // require_same::<u32, i32>(); // T != U: would fail to compile
41/// ```
42#[diagnostic::on_unimplemented(
43 message = "coordinate-system family mismatch: `{Self}` is not the same as `{T}`",
44 label = "this point's coordinate-system family is `{Self}`, but the strategy requires `{T}`",
45 note = "if `{Self}` is `GeographicFamily` or `SphericalFamily`, you probably picked a \
46 Cartesian-only strategy (e.g. `Pythagoras`) by accident — wrap your point in \
47 `geometry_adapt::WithCs<_, Geographic<Degree>>` / `WithCs<_, Spherical<Degree>>` \
48 or pick a CS-appropriate strategy (`Haversine`, `Andoyer`, `Vincenty`)",
49 note = "see the silent-Cartesian discussion in the rust-port proposal §3.7 and §8"
50)]
51pub trait SameAs<T>: sealed::Sealed<T> {}
52
53impl<T> sealed::Sealed<T> for T {}
54impl<T> SameAs<T> for T {}