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    /// Removes per-feature state selected for this session.
58    pub fn remove_feature_state(&self, selector: &FeatureStateSelector) -> Result<()> {
59        self.inner.ensure_no_frame_acquired()?;
60        let session = self.inner.as_ptr()?;
61        let selector = selector.to_native();
62        // SAFETY: session is live and selector owns all call-scoped storage
63        // until the native call returns.
64        maplibre_core::check(unsafe {
65            sys::mln_render_session_remove_feature_state(session, selector.as_ptr())
66        })
67    }
68
69    /// Queries rendered features from the latest render session state.
70    pub fn query_rendered_features(
71        &self,
72        geometry: &RenderedQueryGeometry,
73        options: Option<&RenderedFeatureQueryOptions>,
74    ) -> Result<Vec<QueriedFeature>> {
75        self.inner.ensure_no_frame_acquired()?;
76        let session = self.inner.as_ptr()?;
77        let geometry = geometry.to_native();
78        let options = options
79            .map(RenderedFeatureQueryOptions::to_native)
80            .transpose()?;
81        let mut out = maplibre_core::ptr::OutPtr::<sys::mln_feature_query_result>::new();
82        // SAFETY: session is live; geometry and options retain all borrowed
83        // descriptor storage for the call; out is a null-initialized owned
84        // out-pointer.
85        maplibre_core::check(unsafe {
86            sys::mln_render_session_query_rendered_features(
87                session,
88                geometry.as_ptr(),
89                options
90                    .as_ref()
91                    .map_or(ptr::null(), NativeRenderedFeatureQueryOptions::as_ptr),
92                out.as_mut_ptr(),
93            )
94        })?;
95        // SAFETY: On success, the C API returns an owned feature-query result
96        // handle; core copies and releases it.
97        unsafe {
98            maplibre_core::query::copy_feature_query_result(
99                out.into_non_null("mln_feature_query_result")?,
100            )
101        }
102    }
103
104    /// Queries source features from the latest render session state.
105    pub fn query_source_features(
106        &self,
107        source_id: &str,
108        options: Option<&SourceFeatureQueryOptions>,
109    ) -> Result<Vec<QueriedFeature>> {
110        self.inner.ensure_no_frame_acquired()?;
111        let session = self.inner.as_ptr()?;
112        let source_id = maplibre_core::string::string_view(source_id);
113        let options = options
114            .map(SourceFeatureQueryOptions::to_native)
115            .transpose()?;
116        let mut out = maplibre_core::ptr::OutPtr::<sys::mln_feature_query_result>::new();
117        // SAFETY: session is live; source_id and options retain all borrowed
118        // descriptor storage for the call; out is a null-initialized owned
119        // out-pointer.
120        maplibre_core::check(unsafe {
121            sys::mln_render_session_query_source_features(
122                session,
123                source_id.raw(),
124                options
125                    .as_ref()
126                    .map_or(ptr::null(), NativeSourceFeatureQueryOptions::as_ptr),
127                out.as_mut_ptr(),
128            )
129        })?;
130        // SAFETY: On success, the C API returns an owned feature-query result
131        // handle; core copies and releases it.
132        unsafe {
133            maplibre_core::query::copy_feature_query_result(
134                out.into_non_null("mln_feature_query_result")?,
135            )
136        }
137    }
138
139    /// Queries a feature extension from the latest render session state.
140    pub fn query_feature_extension(
141        &self,
142        source_id: &str,
143        feature: &Feature,
144        extension: &str,
145        extension_field: &str,
146        arguments: Option<&JsonValue>,
147    ) -> Result<FeatureExtensionResult> {
148        self.inner.ensure_no_frame_acquired()?;
149        let session = self.inner.as_ptr()?;
150        let source_id = maplibre_core::string::string_view(source_id);
151        let extension = maplibre_core::string::string_view(extension);
152        let extension_field = maplibre_core::string::string_view(extension_field);
153        let feature = feature.try_to_native(0)?;
154        if let Some(arguments) = arguments
155            && !matches!(arguments, JsonValue::Object(_))
156        {
157            return Err(crate::Error::invalid_argument(
158                "feature extension arguments must be a JSON object",
159            ));
160        }
161        let arguments = arguments.map(JsonValue::try_to_native).transpose()?;
162        let mut out = maplibre_core::ptr::OutPtr::<sys::mln_feature_extension_result>::new();
163        // SAFETY: session is live; all string, feature, and optional JSON
164        // descriptors retain borrowed storage for the call; out is a
165        // null-initialized owned out-pointer.
166        maplibre_core::check(unsafe {
167            sys::mln_render_session_query_feature_extensions(
168                session,
169                source_id.raw(),
170                feature.as_ptr(),
171                extension.raw(),
172                extension_field.raw(),
173                arguments
174                    .as_ref()
175                    .map_or(ptr::null(), crate::json::NativeJsonValue::as_ptr),
176                out.as_mut_ptr(),
177            )
178        })?;
179        // SAFETY: On success, the C API returns an owned feature-extension
180        // result handle; core copies and releases it.
181        unsafe {
182            maplibre_core::query::copy_feature_extension_result(
183                out.into_non_null("mln_feature_extension_result")?,
184            )
185        }
186    }
187}