emf_core_base_rs/module/
native_module.rs

1//! API of a native module.
2use crate::ffi::collections::NonNullConst;
3use crate::ffi::module::native_module::{
4    NativeModule as NativeModuleFFI, NativeModuleBinding,
5    NativeModuleInterface as NativeModuleInterfaceFFI,
6};
7use crate::ffi::CBaseBinding;
8use crate::module::{Error, Interface, InterfaceDescriptor, Module, ModuleInfo};
9use crate::ownership::{
10    AccessIdentifier, BorrowImmutable, BorrowMutable, ImmutableAccessIdentifier,
11    MutableAccessIdentifier, Owned,
12};
13use crate::CBaseInterfaceInfo;
14use std::marker::PhantomData;
15use std::ops::{Deref, DerefMut};
16use std::ptr::NonNull;
17
18/// An instance from a native module.
19#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
20pub struct NativeModuleInstance<'a, O> {
21    _handle: Option<NonNull<NativeModuleFFI>>,
22    _phantom: PhantomData<&'a ()>,
23    _ownership: PhantomData<*const O>,
24}
25
26unsafe impl<O> Send for NativeModuleInstance<'_, O> {}
27unsafe impl<O> Sync for NativeModuleInstance<'_, O> {}
28
29impl<O> NativeModuleInstance<'_, O>
30where
31    O: AccessIdentifier,
32{
33    /// Construct a new instance from a handle.
34    ///
35    /// # Safety
36    ///
37    /// This function allows the creation of invalid handles
38    /// by bypassing lifetimes.
39    #[inline]
40    pub const unsafe fn new(handle: Option<NonNull<NativeModuleFFI>>) -> Self {
41        Self {
42            _handle: handle,
43            _phantom: PhantomData,
44            _ownership: PhantomData,
45        }
46    }
47
48    /// Fetches the internal handle.
49    #[inline]
50    pub const fn as_handle(&self) -> Option<NonNull<NativeModuleFFI>> {
51        self._handle
52    }
53}
54
55impl NativeModuleInstance<'_, Owned> {
56    /// Borrows the instance.
57    #[inline]
58    pub const fn as_borrowed(&self) -> NativeModuleInstance<'_, BorrowImmutable<'_>> {
59        unsafe { NativeModuleInstance::<BorrowImmutable<'_>>::new(self._handle) }
60    }
61
62    /// Borrows the instance mutably.
63    #[inline]
64    pub fn as_borrowed_mut(&mut self) -> NativeModuleInstance<'_, BorrowMutable<'_>> {
65        unsafe { NativeModuleInstance::<BorrowMutable<'_>>::new(self._handle) }
66    }
67}
68
69/// A native module.
70#[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq)]
71pub struct NativeModule<'a, O> {
72    _interface: NonNullConst<NativeModuleInterfaceFFI>,
73    _phantom: PhantomData<&'a ()>,
74    _ownership: PhantomData<*const O>,
75}
76
77unsafe impl<O> Send for NativeModule<'_, O> {}
78unsafe impl<O> Sync for NativeModule<'_, O> {}
79
80impl<O> Deref for NativeModule<'_, O> {
81    type Target = NonNullConst<NativeModuleInterfaceFFI>;
82
83    fn deref(&self) -> &Self::Target {
84        &self._interface
85    }
86}
87
88impl<O> DerefMut for NativeModule<'_, O> {
89    fn deref_mut(&mut self) -> &mut Self::Target {
90        &mut self._interface
91    }
92}
93
94impl<O> NativeModule<'_, O>
95where
96    O: AccessIdentifier,
97{
98    /// Construct a new instance from an interface.
99    ///
100    /// # Safety
101    ///
102    /// This function allows the creation of invalid modules
103    /// by bypassing lifetimes.
104    #[inline]
105    pub const unsafe fn new(interface: NonNullConst<NativeModuleInterfaceFFI>) -> Self {
106        Self {
107            _interface: interface,
108            _phantom: PhantomData,
109            _ownership: PhantomData,
110        }
111    }
112}
113
114impl NativeModule<'_, Owned> {
115    /// Borrows the module interface.
116    #[inline]
117    pub const fn as_borrowed(&self) -> NativeModule<'_, BorrowImmutable<'_>> {
118        unsafe { NativeModule::<'_, BorrowImmutable<'_>>::new(self._interface) }
119    }
120
121    /// Borrows the module interface mutably.
122    #[inline]
123    pub fn as_borrowed_mut(&mut self) -> NativeModule<'_, BorrowMutable<'_>> {
124        unsafe { NativeModule::<'_, BorrowMutable<'_>>::new(self._interface) }
125    }
126}
127
128impl<'a, O> NativeModule<'a, O>
129where
130    O: MutableAccessIdentifier,
131{
132    /// Loads the module.
133    ///
134    /// # Failure
135    ///
136    /// The function can fail if some module invariant is not met.
137    ///
138    /// # Return
139    ///
140    /// Handle on success, error otherwise.
141    ///
142    /// # Safety
143    ///
144    /// The function crosses the ffi boundary.
145    /// Direct usage of a [NativeModule] may break some invariants
146    /// of the module api, if not handled with care.
147    #[inline]
148    pub unsafe fn load<MO>(
149        &mut self,
150        module: &Module<'_, MO>,
151        interface: &impl CBaseInterfaceInfo,
152    ) -> Result<NativeModuleInstance<'a, Owned>, Error>
153    where
154        MO: AccessIdentifier,
155    {
156        let internal = interface.internal_interface();
157        let interface_handle = internal.base_module();
158        let has_fn_fn = internal.fetch_has_function_fn();
159        let get_fn_fn = internal.fetch_get_function_fn();
160
161        self._interface
162            .into_mut()
163            .as_mut()
164            .load(module.as_handle(), interface_handle, has_fn_fn, get_fn_fn)
165            .map_or_else(
166                |e| Err(Error::FFIError(e)),
167                |v| Ok(NativeModuleInstance::new(v)),
168            )
169    }
170
171    /// Unloads the module.
172    ///
173    /// # Failure
174    ///
175    /// The function can fail if some module invariant is not met or `instance` is invalid.
176    ///
177    /// # Return
178    ///
179    /// Error on failure.
180    ///
181    /// # Safety
182    ///
183    /// The function crosses the ffi boundary.
184    /// Direct usage of a [NativeModule] may break some invariants
185    /// of the module api, if not handled with care.
186    #[inline]
187    pub unsafe fn unload(
188        &mut self,
189        instance: NativeModuleInstance<'_, Owned>,
190    ) -> Result<(), Error> {
191        self._interface
192            .into_mut()
193            .as_mut()
194            .unload(instance.as_handle())
195            .to_result()
196            .map_or_else(|e| Err(Error::FFIError(e)), |_v| Ok(()))
197    }
198
199    /// Initializes the module.
200    ///
201    /// # Failure
202    ///
203    /// The function can fail if some module invariant is not met or `instance` is invalid.
204    ///
205    /// # Return
206    ///
207    /// Error on failure.
208    ///
209    /// # Safety
210    ///
211    /// The function crosses the ffi boundary.
212    /// Direct usage of a [NativeModule] may break some invariants
213    /// of the module api, if not handled with care.
214    #[inline]
215    pub unsafe fn initialize(
216        &mut self,
217        instance: &mut NativeModuleInstance<'_, Owned>,
218    ) -> Result<(), Error> {
219        self._interface
220            .into_mut()
221            .as_mut()
222            .initialize(instance.as_handle())
223            .to_result()
224            .map_or_else(|e| Err(Error::FFIError(e)), |_v| Ok(()))
225    }
226
227    /// Terminates the module.
228    ///
229    /// # Failure
230    ///
231    /// The function can fail if some module invariant is not met or `instance` is invalid.
232    ///
233    /// # Return
234    ///
235    /// Error on failure.
236    ///
237    /// # Safety
238    ///
239    /// The function crosses the ffi boundary.
240    /// Direct usage of a [NativeModule] may break some invariants
241    /// of the module api, if not handled with care.
242    #[inline]
243    pub unsafe fn terminate(
244        &mut self,
245        instance: &mut NativeModuleInstance<'_, Owned>,
246    ) -> Result<(), Error> {
247        self._interface
248            .into_mut()
249            .as_mut()
250            .terminate(instance.as_handle())
251            .to_result()
252            .map_or_else(|e| Err(Error::FFIError(e)), |_v| Ok(()))
253    }
254}
255
256impl<'a, O> NativeModule<'a, O>
257where
258    O: ImmutableAccessIdentifier,
259{
260    /// Fetches an interface from the module.
261    ///
262    /// # Failure
263    ///
264    /// The function fails if `instance` is invalid.
265    ///
266    /// # Return
267    ///
268    /// Interface on success, error otherwise.
269    ///
270    /// # Safety
271    ///
272    /// The function is not thread-safe and crosses the ffi boundary.
273    /// Direct usage of a [NativeModule] may break some invariants
274    /// of the module api, if not handled with care.
275    #[inline]
276    pub unsafe fn get_interface<'instance, IO, T>(
277        &self,
278        instance: &'instance NativeModuleInstance<'instance, IO>,
279        interface: &InterfaceDescriptor,
280        caster: impl FnOnce(crate::ffi::module::Interface) -> T,
281    ) -> Result<Interface<'instance, T>, Error>
282    where
283        IO: ImmutableAccessIdentifier,
284    {
285        self._interface
286            .as_ref()
287            .get_interface(instance.as_handle(), NonNullConst::from(interface))
288            .to_result()
289            .map_or_else(
290                |e| Err(Error::FFIError(e)),
291                |v| Ok(Interface::new(caster(v))),
292            )
293    }
294
295    /// Fetches the module info of the module.
296    ///
297    /// # Failure
298    ///
299    /// The function fails if `instance` is invalid.
300    ///
301    /// # Return
302    ///
303    /// Module info on success, error otherwise.
304    ///
305    /// # Safety
306    ///
307    /// The function is not thread-safe and crosses the ffi boundary.
308    /// Direct usage of a [NativeModule] may break some invariants
309    /// of the module api, if not handled with care.
310    #[inline]
311    pub unsafe fn get_module_info<'instance, IO>(
312        &self,
313        instance: &'instance NativeModuleInstance<'instance, IO>,
314    ) -> Result<&'instance ModuleInfo, Error>
315    where
316        IO: ImmutableAccessIdentifier,
317    {
318        self._interface
319            .as_ref()
320            .get_module_info(instance.as_handle())
321            .to_result()
322            .map_or_else(|e| Err(Error::FFIError(e)), |v| Ok(&*v.as_ptr()))
323    }
324
325    /// Fetches the load dependencies of the module.
326    ///
327    /// # Return
328    ///
329    /// Load dependencies.
330    ///
331    /// # Safety
332    ///
333    /// The function crosses the ffi boundary.
334    /// Direct usage of a [NativeModule] may break some invariants
335    /// of the module api, if not handled with care.
336    #[inline]
337    pub unsafe fn get_load_dependencies(&self) -> &'a [InterfaceDescriptor] {
338        let span = self._interface.as_ref().get_load_dependencies();
339        if span.is_empty() {
340            <&[_]>::default()
341        } else {
342            std::slice::from_raw_parts(span.as_ptr(), span.len())
343        }
344    }
345
346    /// Fetches the runtime dependencies of the module.
347    ///
348    /// # Failure
349    ///
350    /// The function fails if `instance` is invalid.
351    ///
352    /// # Return
353    ///
354    /// Runtime dependencies on success, error otherwise.
355    ///
356    /// # Safety
357    ///
358    /// The function is not thread-safe and crosses the ffi boundary.
359    /// Direct usage of a [NativeModule] may break some invariants
360    /// of the module api, if not handled with care.
361    #[inline]
362    pub unsafe fn get_runtime_dependencies<'instance, IO>(
363        &self,
364        instance: &'instance NativeModuleInstance<'instance, IO>,
365    ) -> Result<&'instance [InterfaceDescriptor], Error>
366    where
367        IO: ImmutableAccessIdentifier,
368    {
369        self._interface
370            .as_ref()
371            .get_runtime_dependencies(instance.as_handle())
372            .to_result()
373            .map_or_else(
374                |e| Err(Error::FFIError(e)),
375                |v| {
376                    if v.is_empty() {
377                        Ok(<&[_]>::default())
378                    } else {
379                        Ok(std::slice::from_raw_parts(v.as_ptr(), v.len()))
380                    }
381                },
382            )
383    }
384
385    /// Fetches the exportable interfaces of the module.
386    ///
387    /// # Failure
388    ///
389    /// The function fails if `instance` is invalid.
390    ///
391    /// # Return
392    ///
393    /// Exportable interfaces on success, error otherwise.
394    ///
395    /// # Safety
396    ///
397    /// The function is not thread-safe and crosses the ffi boundary.
398    /// Direct usage of a [NativeModule] may break some invariants
399    /// of the module api, if not handled with care.
400    #[inline]
401    pub unsafe fn get_exportable_interfaces<'instance, IO>(
402        &self,
403        instance: &'instance NativeModuleInstance<'instance, IO>,
404    ) -> Result<&'instance [InterfaceDescriptor], Error>
405    where
406        IO: ImmutableAccessIdentifier,
407    {
408        self._interface
409            .as_ref()
410            .get_exportable_interfaces(instance.as_handle())
411            .to_result()
412            .map_or_else(
413                |e| Err(Error::FFIError(e)),
414                |v| {
415                    if v.is_empty() {
416                        Ok(<&[_]>::default())
417                    } else {
418                        Ok(std::slice::from_raw_parts(v.as_ptr(), v.len()))
419                    }
420                },
421            )
422    }
423}