fission_core/
platform_geolocation.rs1use crate::capability::{CapabilityType, OperationCapability};
4use serde::{Deserialize, Serialize};
5
6#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
7pub enum GeolocationPermission {
8 Granted,
9 Denied,
10 Prompt,
11 #[default]
12 Unknown,
13 Unsupported,
14}
15
16#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
17pub struct GeolocationPermissionRequest {
18 pub precise: bool,
19 pub background: bool,
20}
21
22#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
23pub struct GeolocationPositionRequest {
24 pub high_accuracy: bool,
25 pub timeout_ms: Option<u64>,
26 pub maximum_age_ms: Option<u64>,
27}
28
29#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
30pub struct GeolocationPosition {
31 pub latitude: f64,
32 pub longitude: f64,
33 pub altitude_meters: Option<f64>,
34 pub accuracy_meters: f64,
35 pub altitude_accuracy_meters: Option<f64>,
36 pub heading_degrees: Option<f64>,
37 pub speed_mps: Option<f64>,
38 pub timestamp_unix_ms: u64,
39}
40
41#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
42pub struct GeolocationError {
43 pub code: String,
44 pub message: String,
45}
46
47impl GeolocationError {
48 pub fn new(code: impl Into<String>, message: impl Into<String>) -> Self {
55 Self {
56 code: code.into(),
57 message: message.into(),
58 }
59 }
60
61 pub fn unsupported(operation: impl Into<String>) -> Self {
67 Self::new(
68 "unsupported",
69 format!(
70 "geolocation operation `{}` is not supported by this host",
71 operation.into()
72 ),
73 )
74 }
75}
76
77pub struct GetGeolocationPermissionCapability;
78impl OperationCapability for GetGeolocationPermissionCapability {
79 type Request = ();
80 type Ok = GeolocationPermission;
81 type Err = GeolocationError;
82}
83
84pub struct RequestGeolocationPermissionCapability;
85impl OperationCapability for RequestGeolocationPermissionCapability {
86 type Request = GeolocationPermissionRequest;
87 type Ok = GeolocationPermission;
88 type Err = GeolocationError;
89}
90
91pub struct GetCurrentPositionCapability;
92impl OperationCapability for GetCurrentPositionCapability {
93 type Request = GeolocationPositionRequest;
94 type Ok = GeolocationPosition;
95 type Err = GeolocationError;
96}
97
98pub const GET_GEOLOCATION_PERMISSION: CapabilityType<GetGeolocationPermissionCapability> =
99 CapabilityType::new("fission.geolocation.get_permission");
100pub const REQUEST_GEOLOCATION_PERMISSION: CapabilityType<RequestGeolocationPermissionCapability> =
101 CapabilityType::new("fission.geolocation.request_permission");
102pub const GET_CURRENT_POSITION: CapabilityType<GetCurrentPositionCapability> =
103 CapabilityType::new("fission.geolocation.get_current_position");
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn geolocation_request_round_trips() {
111 let request = GeolocationPositionRequest {
112 high_accuracy: true,
113 timeout_ms: Some(5_000),
114 maximum_age_ms: Some(30_000),
115 };
116 let bytes = serde_json::to_vec(&request).unwrap();
117 let decoded: GeolocationPositionRequest = serde_json::from_slice(&bytes).unwrap();
118 assert_eq!(decoded, request);
119 }
120
121 #[test]
122 fn geolocation_position_round_trips() {
123 let position = GeolocationPosition {
124 latitude: 51.5074,
125 longitude: -0.1278,
126 altitude_meters: None,
127 accuracy_meters: 8.0,
128 altitude_accuracy_meters: None,
129 heading_degrees: None,
130 speed_mps: None,
131 timestamp_unix_ms: 1_774_000_000_000,
132 };
133 let bytes = serde_json::to_vec(&position).unwrap();
134 let decoded: GeolocationPosition = serde_json::from_slice(&bytes).unwrap();
135 assert_eq!(decoded, position);
136 }
137}