Skip to main content

azul_core/
geolocation.rs

1//! POD types for the geolocation surface. Defined here in `azul-core`
2//! so `NodeType::GeolocationProbe(GeolocationProbeConfig)` can carry the
3//! config without `azul-layout` having to be a `azul-core` dependency.
4//!
5//! The stateful side (refcount, diff queue, latest-fix storage) lives
6//! in `azul_layout::managers::geolocation::GeolocationManager` and
7//! re-exports these types for the existing import paths.
8
9/// One GPS / network-located fix. Mirrors the W3C
10/// [`GeolocationPosition`](https://www.w3.org/TR/geolocation/#position_interface)
11/// shape so the future web backend lands without API churn.
12///
13/// `accuracy_m` is the 1-sigma radius in metres. `altitude_m` /
14/// `altitude_accuracy_m` / `heading_deg` / `speed_mps` are reported as
15/// `f32::NAN` when the platform doesn't supply them — iOS / Android
16/// always supply lat/lon but the other fields depend on hardware.
17#[derive(Debug, Clone, Copy, PartialEq)]
18#[repr(C)]
19pub struct LocationFix {
20    /// Latitude in WGS-84 degrees (positive = north, negative = south).
21    pub latitude_deg: f64,
22    /// Longitude in WGS-84 degrees (positive = east, negative = west).
23    pub longitude_deg: f64,
24    /// 1-sigma horizontal accuracy radius in metres.
25    pub accuracy_m: f32,
26    /// Altitude above the WGS-84 ellipsoid in metres. `NaN` if not
27    /// reported (the platform couldn't measure it).
28    pub altitude_m: f32,
29    /// 1-sigma altitude accuracy in metres. `NaN` if `altitude_m` is
30    /// `NaN` or the platform doesn't report it.
31    pub altitude_accuracy_m: f32,
32    /// Bearing in degrees clockwise from true north, `0..360`. `NaN`
33    /// if the device is stationary or the platform doesn't report it.
34    pub heading_deg: f32,
35    /// Ground speed in metres per second. `NaN` if not reported.
36    pub speed_mps: f32,
37    /// Monotonic timestamp in milliseconds since program start. Lets
38    /// callers detect stale fixes without depending on wall-clock time.
39    pub timestamp_ms: u64,
40}
41
42// FFI Option wrapper (mirrors OptionPenState). Lets `CallbackInfo::
43// get_location_fix() -> Option<LocationFix>` cross the C ABI once the
44// matching api.json type entry + getter are registered via the autofix
45// workflow. Unused internally today; this is the no-codegen prerequisite
46// for that exposure (see MOBILE_SESSION_LOG P3.1h).
47impl_option!(LocationFix, OptionLocationFix, [Debug, Clone, Copy, PartialEq]);
48
49impl LocationFix {
50    pub fn altitude(&self) -> Option<f32> {
51        if self.altitude_m.is_nan() {
52            None
53        } else {
54            Some(self.altitude_m)
55        }
56    }
57
58    pub fn altitude_accuracy(&self) -> Option<f32> {
59        if self.altitude_accuracy_m.is_nan() {
60            None
61        } else {
62            Some(self.altitude_accuracy_m)
63        }
64    }
65
66    pub fn heading(&self) -> Option<f32> {
67        if self.heading_deg.is_nan() {
68            None
69        } else {
70            Some(self.heading_deg)
71        }
72    }
73
74    pub fn speed(&self) -> Option<f32> {
75        if self.speed_mps.is_nan() {
76            None
77        } else {
78            Some(self.speed_mps)
79        }
80    }
81}
82
83/// Configuration the user attaches to a `NodeType::GeolocationProbe`
84/// to tune the platform subscription. Maps to W3C `PositionOptions`
85/// (`enableHighAccuracy` + `maximumAge` + `timeout`).
86#[derive(Debug, Clone, Copy, PartialEq)]
87#[repr(C)]
88pub struct GeolocationProbeConfig {
89    /// `true` requests precise (GPS-driven) location. iOS maps this to
90    /// `CLLocationManager.desiredAccuracy = kCLLocationAccuracyBest`;
91    /// Android to `LocationRequest.PRIORITY_HIGH_ACCURACY`. Costs
92    /// battery — leave `false` for city-block-level apps.
93    pub high_accuracy: bool,
94    /// Subscribe to *background* location updates. Requires extra
95    /// per-platform manifest declarations and a separate
96    /// `Capability::GeolocationBackground` permission grant. `false`
97    /// is the safe default.
98    pub background: bool,
99    /// Reject any fix whose `accuracy_m` exceeds this radius. `0`
100    /// disables the filter — every native sample is delivered.
101    pub max_accuracy_m: f32,
102    /// Minimum time between delivered updates, in milliseconds. `0`
103    /// disables throttling (every native sample is delivered;
104    /// expensive when the platform fires at 10 Hz indoors).
105    pub min_interval_ms: u32,
106}
107
108impl Default for GeolocationProbeConfig {
109    fn default() -> Self {
110        Self {
111            high_accuracy: false,
112            background: false,
113            max_accuracy_m: 0.0,
114            min_interval_ms: 0,
115        }
116    }
117}
118
119impl Eq for GeolocationProbeConfig {}
120
121impl PartialOrd for GeolocationProbeConfig {
122    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
123        Some(self.cmp(other))
124    }
125}
126
127impl Ord for GeolocationProbeConfig {
128    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
129        // f32 comparison via to_bits — gives a total order even with
130        // NaNs and matches NodeType::Eq + Hash requirements.
131        (
132            self.high_accuracy,
133            self.background,
134            self.max_accuracy_m.to_bits(),
135            self.min_interval_ms,
136        )
137            .cmp(&(
138                other.high_accuracy,
139                other.background,
140                other.max_accuracy_m.to_bits(),
141                other.min_interval_ms,
142            ))
143    }
144}
145
146impl core::hash::Hash for GeolocationProbeConfig {
147    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
148        self.high_accuracy.hash(state);
149        self.background.hash(state);
150        self.max_accuracy_m.to_bits().hash(state);
151        self.min_interval_ms.hash(state);
152    }
153}