Skip to main content

maplibre_native_ffi/
call.rs

1//! Keep the receiver and input storage live through the native call. Copy
2//! borrowed outputs before the call returns, or tie them to a view scope.
3
4use std::ffi::c_void;
5
6use maplibre_native_ffi_sys::{self as sys, NativeHandle};
7
8use crate::Result;
9use crate::completion::{self, CommandCompletion, NativeFuture};
10use crate::convert::{self, InputArena, ToNative};
11
12pub(crate) struct Call<'a, H: NativeHandle> {
13    native: H,
14    // The receiver stays alive while borrowed output is copied.
15    _owner: std::marker::PhantomData<&'a H>,
16    arena: InputArena,
17}
18
19impl Call<'static, ()> {
20    pub(crate) fn global() -> Self {
21        Self::new(())
22    }
23}
24
25impl<'a, H: NativeHandle> Call<'a, H> {
26    pub(crate) fn new(native: H) -> Self {
27        Self {
28            native,
29            _owner: std::marker::PhantomData,
30            arena: InputArena::default(),
31        }
32    }
33
34    pub(crate) fn input<N, T: ToNative<N> + ?Sized>(&mut self, value: &T) -> Result<N> {
35        value.to_native(&mut self.arena)
36    }
37
38    pub(crate) fn array<N: 'static, T: ToNative<N>>(&mut self, values: &[T]) -> Result<*const N> {
39        convert::array(values, &mut self.arena)
40    }
41
42    pub(crate) fn reference<N: 'static, T: ToNative<N> + ?Sized>(
43        &mut self,
44        value: &T,
45    ) -> Result<*const N> {
46        convert::reference(value, &mut self.arena)
47    }
48
49    pub(crate) fn optional_reference<N: 'static, T: ToNative<N> + ?Sized>(
50        &mut self,
51        value: Option<&T>,
52    ) -> Result<*const N> {
53        convert::optional_reference(value, &mut self.arena)
54    }
55
56    /// Makes a call that returns a status. The call's read and view stay
57    /// open until it drops, so outputs that borrow native storage are copied
58    /// before it does.
59    pub(crate) fn status(
60        &mut self,
61        call: impl FnOnce(H, *mut sys::mln_diagnostic) -> sys::mln_status,
62    ) -> Result<()> {
63        crate::error::check(|diagnostic| call(self.native, diagnostic))?;
64        self.arena.accept_registrations();
65        Ok(())
66    }
67
68    /// Keeps registration roots pending when native reports that it kept none.
69    pub(crate) fn status_registered(
70        &mut self,
71        call: impl FnOnce(H, *mut sys::mln_diagnostic) -> (sys::mln_status, bool),
72    ) -> Result<()> {
73        let mut accepted = false;
74        crate::error::check(|diagnostic| {
75            let (status, retained) = call(self.native, diagnostic);
76            accepted = retained;
77            status
78        })?;
79        if accepted {
80            self.arena.accept_registrations();
81        }
82        Ok(())
83    }
84
85    pub(crate) fn run<R>(&mut self, call: impl FnOnce(H) -> R) -> R {
86        let result = call(self.native);
87        self.arena.accept_registrations();
88        result
89    }
90
91    pub(crate) fn command(
92        self,
93        submit: impl FnOnce(H, *const sys::mln_completion, *mut sys::mln_diagnostic) -> sys::mln_status,
94    ) -> Result<NativeFuture<CommandCompletion>> {
95        self.complete(submit, completion::command)
96    }
97
98    pub(crate) fn discard(
99        mut self,
100        submit: impl FnOnce(H, *const sys::mln_completion, *mut sys::mln_diagnostic) -> sys::mln_status,
101    ) -> Result<()> {
102        crate::error::check(|diagnostic| submit(self.native, std::ptr::null(), diagnostic))?;
103        self.arena.accept_registrations();
104        Ok(())
105    }
106
107    pub(crate) fn complete<T: Send + 'static>(
108        mut self,
109        submit: impl FnOnce(H, *const sys::mln_completion, *mut sys::mln_diagnostic) -> sys::mln_status,
110        convert: impl FnOnce(&sys::mln_completion_result) -> Result<T> + Send + 'static,
111    ) -> Result<NativeFuture<T>> {
112        let native = self.native;
113        let future = completion::submit(
114            |completion, diagnostic| submit(native, completion, diagnostic),
115            convert,
116        )?;
117        self.arena.accept_registrations();
118        Ok(future)
119    }
120}
121
122/// A native view scope, which keeps the native objects that its owner's
123/// getters lend valid until it drops. Ending it is allowed on any thread.
124pub(crate) struct ViewScope {
125    token: *mut c_void,
126    end: unsafe extern "C" fn(*mut c_void),
127}
128
129// SAFETY: native ends a scope on any thread, and the token is only passed back
130// to that end.
131unsafe impl Send for ViewScope {}
132// SAFETY: a shared scope exposes nothing.
133unsafe impl Sync for ViewScope {}
134
135impl ViewScope {
136    /// Begins a scope on `native`.
137    ///
138    /// # Safety
139    ///
140    /// The functions must be the matching view scope functions of `H`.
141    pub(crate) unsafe fn begin<H: NativeHandle>(
142        native: H,
143        begin: unsafe extern "C" fn(
144            H,
145            *mut *mut c_void,
146            *mut sys::mln_diagnostic,
147        ) -> sys::mln_status,
148        end: unsafe extern "C" fn(*mut c_void),
149    ) -> Result<Self> {
150        let mut token = std::ptr::null_mut();
151        // SAFETY: the caller passes the scope functions of this handle type.
152        crate::error::check(|diagnostic| unsafe { begin(native, &mut token, diagnostic) })?;
153        Ok(Self { token, end })
154    }
155}
156
157impl Drop for ViewScope {
158    fn drop(&mut self) {
159        // SAFETY: begin issued the token, and the scope ends it once.
160        unsafe { (self.end)(self.token) };
161    }
162}
163
164/// A value that a view getter lends, valid until its view drops.
165///
166/// It reads as the value itself, and its borrow keeps the view open while the
167/// value is held. The native objects that it names, such as a backend
168/// texture, stay valid only while the view lives. Their names are plain data
169/// that can still be copied out, so a name used after the view ends is the
170/// fault of the unsafe graphics call that uses it.
171pub struct Lent<'v, T> {
172    value: T,
173    _view: std::marker::PhantomData<&'v ()>,
174}
175
176impl<T> Lent<'_, T> {
177    pub(crate) fn new(value: T) -> Self {
178        Self {
179            value,
180            _view: std::marker::PhantomData,
181        }
182    }
183}
184
185impl<T> std::ops::Deref for Lent<'_, T> {
186    type Target = T;
187
188    fn deref(&self) -> &T {
189        &self.value
190    }
191}
192
193impl<T: std::fmt::Debug> std::fmt::Debug for Lent<'_, T> {
194    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195        self.value.fmt(f)
196    }
197}