Skip to main content

maplibre_native_ffi/
geojson.rs

1use std::fmt;
2use std::ptr;
3
4use maplibre_native_ffi_core as maplibre_core;
5use maplibre_native_ffi_sys as sys;
6
7use maplibre_core::style::{NativeGeoJsonSourceOptions, geojson_source_options_to_native};
8
9use crate::{GeoJsonSourceOptions, Result};
10
11/// Owned handle for prepared GeoJSON source data.
12///
13/// [`Self::new`] parses one complete UTF-8 GeoJSON document and tiles or
14/// clusters it into the index a GeoJSON source consumes, which is the
15/// expensive part of a data update. It needs no runtime or map and runs on
16/// any thread, so a host prepares data on a worker thread and installs it on
17/// the map owner thread through
18/// [`crate::MapHandle::add_geojson_source_data`] or
19/// [`crate::MapHandle::set_geojson_source_data`].
20///
21/// The options are baked into the prepared data and must match the options of
22/// every source the data is installed on. Installing borrows the handle, so
23/// one prepared value may be installed on any number of sources; dropping or
24/// closing it afterwards never invalidates a source, because sources keep
25/// their own reference.
26pub struct GeoJsonSourceDataHandle {
27    handle: sys::mln_geojson_source_data,
28}
29
30// SAFETY: The prepared native data is immutable, and the C API documents
31// create, read, and destroy as callable from any thread.
32unsafe impl Send for GeoJsonSourceDataHandle {}
33// SAFETY: Shared reads only pass the immutable handle id across the C
34// boundary, and release requires exclusive ownership (`Drop` or `close`).
35unsafe impl Sync for GeoJsonSourceDataHandle {}
36
37impl fmt::Debug for GeoJsonSourceDataHandle {
38    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39        f.debug_struct("GeoJsonSourceDataHandle")
40            .finish_non_exhaustive()
41    }
42}
43
44impl GeoJsonSourceDataHandle {
45    /// Prepares GeoJSON source data. `options` may be `None` for defaults.
46    ///
47    /// When `options` enable clustering, the data must be a feature collection
48    /// whose every feature carries point geometry; anything else is rejected
49    /// with an invalid-argument error naming the constraint.
50    pub fn new(data: &[u8], options: Option<&GeoJsonSourceOptions>) -> Result<Self> {
51        let data = maplibre_core::string::buffer_view(data);
52        let options = options.map(geojson_source_options_to_native).transpose()?;
53        let options_ptr = options
54            .as_ref()
55            .map_or(ptr::null(), NativeGeoJsonSourceOptions::as_ptr);
56        let mut out = maplibre_core::ptr::OutHandle::<sys::mln_geojson_source_data>::new();
57        // SAFETY: data and the optional native options are valid for this call,
58        // and out is a null-initialized out-pointer owned by this call.
59        maplibre_core::check(unsafe {
60            sys::mln_geojson_source_data_create(data, options_ptr, out.as_mut_ptr())
61        })?;
62        Ok(Self {
63            handle: out.into_live("mln_geojson_source_data")?,
64        })
65    }
66
67    /// The live native handle, borrowed by map install calls.
68    pub(crate) fn native(&self) -> sys::mln_geojson_source_data {
69        self.handle
70    }
71
72    /// Releases the prepared data. Sources it was installed on keep their own
73    /// reference and stay valid. Dropping the handle releases it the same way.
74    pub fn close(self) {
75        drop(self);
76    }
77}
78
79impl Drop for GeoJsonSourceDataHandle {
80    fn drop(&mut self) {
81        // SAFETY: handle is the owned live handle this wrapper was constructed
82        // with; ownership makes this the only release, and the C API accepts
83        // release from any thread.
84        unsafe { sys::mln_geojson_source_data_destroy(self.handle) };
85    }
86}