Skip to main content

maplibre_native/render/
query.rs

1use std::ptr;
2
3use maplibre_native_core as maplibre_core;
4use maplibre_native_sys as sys;
5
6use crate::Result;
7use crate::geojson::{Feature, FeatureNativeExt};
8use crate::json::{JsonValue, JsonValueNativeExt};
9
10pub use maplibre_core::query::{
11    FeatureExtensionResult, FeatureStateSelector, QueriedFeature, RenderedFeatureQueryOptions,
12    RenderedQueryGeometry, SourceFeatureQueryOptions,
13};
14pub(crate) use maplibre_core::query::{
15    FeatureStateSelectorNativeExt, NativeRenderedFeatureQueryOptions,
16    NativeSourceFeatureQueryOptions, RenderedFeatureQueryOptionsNativeExt,
17    RenderedQueryGeometryNativeExt, SourceFeatureQueryOptionsNativeExt,
18};
19
20impl super::RenderSessionHandle {
21    /// Sets per-feature state on a render source for this session.
22    pub fn set_feature_state(
23        &self,
24        selector: &FeatureStateSelector,
25        state: &JsonValue,
26    ) -> Result<()> {
27        self.inner.ensure_no_frame_acquired()?;
28        let session = self.inner.as_ptr()?;
29        let selector = selector.to_native();
30        let state = state.try_to_native()?;
31        // SAFETY: session is live. selector and state own all call-scoped
32        // descriptor storage until the native call returns.
33        maplibre_core::check(unsafe {
34            sys::mln_render_session_set_feature_state(session, selector.as_ptr(), state.as_ptr())
35        })
36    }
37
38    /// Copies per-feature state from a render source in this session.
39    pub fn get_feature_state(&self, selector: &FeatureStateSelector) -> Result<JsonValue> {
40        self.inner.ensure_no_frame_acquired()?;
41        let session = self.inner.as_ptr()?;
42        let selector = selector.to_native();
43        let mut out = maplibre_core::ptr::OutPtr::<sys::mln_json_snapshot>::new();
44        // SAFETY: session is live, selector owns call-scoped storage, and out
45        // is a null-initialized out-pointer owned by this call.
46        maplibre_core::check(unsafe {
47            sys::mln_render_session_get_feature_state(session, selector.as_ptr(), out.as_mut_ptr())
48        })?;
49        // SAFETY: On success, the C API returns either null or an owned JSON
50        // snapshot handle for this call; core copies and releases it.
51        Ok(
52            unsafe { maplibre_core::json::copy_json_snapshot(out.into_option()) }?
53                .unwrap_or_else(|| JsonValue::Object(Vec::new())),
54        )
55    }
56
57    /// Copies per-feature state from a render source in this session.
58    pub fn feature_state(&self, selector: &FeatureStateSelector) -> Result<JsonValue> {
59        self.get_feature_state(selector)
60    }
61
62    /// Removes per-feature state selected for this session.
63    pub fn remove_feature_state(&self, selector: &FeatureStateSelector) -> Result<()> {
64        self.inner.ensure_no_frame_acquired()?;
65        let session = self.inner.as_ptr()?;
66        let selector = selector.to_native();
67        // SAFETY: session is live and selector owns all call-scoped storage
68        // until the native call returns.
69        maplibre_core::check(unsafe {
70            sys::mln_render_session_remove_feature_state(session, selector.as_ptr())
71        })
72    }
73
74    /// Queries rendered features from the latest render session state.
75    pub fn query_rendered_features(
76        &self,
77        geometry: &RenderedQueryGeometry,
78        options: Option<&RenderedFeatureQueryOptions>,
79    ) -> Result<Vec<QueriedFeature>> {
80        self.inner.ensure_no_frame_acquired()?;
81        let session = self.inner.as_ptr()?;
82        let geometry = geometry.to_native();
83        let options = options
84            .map(RenderedFeatureQueryOptions::to_native)
85            .transpose()?;
86        let mut out = maplibre_core::ptr::OutPtr::<sys::mln_feature_query_result>::new();
87        // SAFETY: session is live; geometry and options retain all borrowed
88        // descriptor storage for the call; out is a null-initialized owned
89        // out-pointer.
90        maplibre_core::check(unsafe {
91            sys::mln_render_session_query_rendered_features(
92                session,
93                geometry.as_ptr(),
94                options
95                    .as_ref()
96                    .map_or(ptr::null(), NativeRenderedFeatureQueryOptions::as_ptr),
97                out.as_mut_ptr(),
98            )
99        })?;
100        // SAFETY: On success, the C API returns an owned feature-query result
101        // handle; core copies and releases it.
102        unsafe {
103            maplibre_core::query::copy_feature_query_result(
104                out.into_non_null("mln_feature_query_result")?,
105            )
106        }
107    }
108
109    /// Queries source features from the latest render session state.
110    pub fn query_source_features(
111        &self,
112        source_id: &str,
113        options: Option<&SourceFeatureQueryOptions>,
114    ) -> Result<Vec<QueriedFeature>> {
115        self.inner.ensure_no_frame_acquired()?;
116        let session = self.inner.as_ptr()?;
117        let source_id = maplibre_core::string::string_view(source_id);
118        let options = options
119            .map(SourceFeatureQueryOptions::to_native)
120            .transpose()?;
121        let mut out = maplibre_core::ptr::OutPtr::<sys::mln_feature_query_result>::new();
122        // SAFETY: session is live; source_id and options retain all borrowed
123        // descriptor storage for the call; out is a null-initialized owned
124        // out-pointer.
125        maplibre_core::check(unsafe {
126            sys::mln_render_session_query_source_features(
127                session,
128                source_id.raw(),
129                options
130                    .as_ref()
131                    .map_or(ptr::null(), NativeSourceFeatureQueryOptions::as_ptr),
132                out.as_mut_ptr(),
133            )
134        })?;
135        // SAFETY: On success, the C API returns an owned feature-query result
136        // handle; core copies and releases it.
137        unsafe {
138            maplibre_core::query::copy_feature_query_result(
139                out.into_non_null("mln_feature_query_result")?,
140            )
141        }
142    }
143
144    /// Queries a feature extension from the latest render session state.
145    pub fn query_feature_extension(
146        &self,
147        source_id: &str,
148        feature: &Feature,
149        extension: &str,
150        extension_field: &str,
151        arguments: Option<&JsonValue>,
152    ) -> Result<FeatureExtensionResult> {
153        self.inner.ensure_no_frame_acquired()?;
154        let session = self.inner.as_ptr()?;
155        let source_id = maplibre_core::string::string_view(source_id);
156        let extension = maplibre_core::string::string_view(extension);
157        let extension_field = maplibre_core::string::string_view(extension_field);
158        let feature = feature.try_to_native(0)?;
159        if let Some(arguments) = arguments
160            && !matches!(arguments, JsonValue::Object(_))
161        {
162            return Err(crate::Error::invalid_argument(
163                "feature extension arguments must be a JSON object",
164            ));
165        }
166        let arguments = arguments.map(JsonValue::try_to_native).transpose()?;
167        let mut out = maplibre_core::ptr::OutPtr::<sys::mln_feature_extension_result>::new();
168        // SAFETY: session is live; all string, feature, and optional JSON
169        // descriptors retain borrowed storage for the call; out is a
170        // null-initialized owned out-pointer.
171        maplibre_core::check(unsafe {
172            sys::mln_render_session_query_feature_extensions(
173                session,
174                source_id.raw(),
175                feature.as_ptr(),
176                extension.raw(),
177                extension_field.raw(),
178                arguments
179                    .as_ref()
180                    .map_or(ptr::null(), crate::json::NativeJsonValue::as_ptr),
181                out.as_mut_ptr(),
182            )
183        })?;
184        // SAFETY: On success, the C API returns an owned feature-extension
185        // result handle; core copies and releases it.
186        unsafe {
187            maplibre_core::query::copy_feature_extension_result(
188                out.into_non_null("mln_feature_extension_result")?,
189            )
190        }
191    }
192}