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}