bp3d_os/module/library/
symbol.rs

1// Copyright (c) 2025, BlockProject 3D
2//
3// All rights reserved.
4//
5// Redistribution and use in source and binary forms, with or without modification,
6// are permitted provided that the following conditions are met:
7//
8//     * Redistributions of source code must retain the above copyright notice,
9//       this list of conditions and the following disclaimer.
10//     * Redistributions in binary form must reproduce the above copyright notice,
11//       this list of conditions and the following disclaimer in the documentation
12//       and/or other materials provided with the distribution.
13//     * Neither the name of BlockProject 3D nor the names of its contributors
14//       may be used to endorse or promote products derived from this software
15//       without specific prior written permission.
16//
17// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
21// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29//! This module contains helpers for C module symbols.
30
31// Apparently this thing is a false positive for function pointers...
32#![allow(clippy::crosspointer_transmute)]
33
34use std::ffi::c_void;
35use std::marker::PhantomData;
36
37/// This represents a symbol from a [Library](crate::module::library::Library).
38pub struct Symbol<'a, T> {
39    ptr: *const T,
40    useless: PhantomData<&'a ()>,
41}
42
43impl<'a, T> Symbol<'a, T> {
44    /// Creates a new [Symbol] from a raw pointer.
45    ///
46    /// # Arguments
47    ///
48    /// * `val`: the raw pointer.
49    ///
50    /// returns: Symbol<T>
51    ///
52    /// # Safety
53    ///
54    /// This is UB if val does not match the signature of T.
55    #[inline(always)]
56    pub unsafe fn from_raw(val: *const c_void) -> Self {
57        Self {
58            ptr: val as *const T,
59            useless: PhantomData,
60        }
61    }
62
63    /// Returns the raw pointer of this symbol.
64    #[inline(always)]
65    pub fn as_ptr(&self) -> *const T {
66        self.ptr
67    }
68
69    /// Creates a static reference to a symbol.
70    ///
71    /// # Safety
72    ///
73    /// This function assumes that the matching Library this symbol originates from will never ever
74    /// be dropped/unloaded before using the produced static symbol. If the returned symbol is used
75    /// after dropping the matching Library this symbol originated from, this is UB.
76    ///
77    /// This is best ensured using a [ModuleLoader](crate::module::ModuleLoader) rather than messing
78    /// with [Library](crate::module::library::Library) manually.
79    #[inline(always)]
80    pub unsafe fn as_static(&self) -> Symbol<'static, T> {
81        Symbol {
82            ptr: self.ptr,
83            useless: PhantomData,
84        }
85    }
86}
87
88impl<'a, R> Symbol<'a, extern "Rust" fn() -> R> {
89    /// Calls this symbol if this symbol is a function.
90    ///
91    /// returns: R
92    pub fn call(&self) -> R {
93        let f: extern "Rust" fn() -> R = unsafe { std::mem::transmute(self.ptr) };
94        f()
95    }
96}
97
98impl<'a, T, R> Symbol<'a, extern "Rust" fn(T) -> R> {
99    /// Calls this symbol if this symbol is a function.
100    ///
101    /// # Arguments
102    ///
103    /// * `val`: argument #1.
104    ///
105    /// returns: R
106    pub fn call(&self, val: T) -> R {
107        let f: extern "Rust" fn(T) -> R = unsafe { std::mem::transmute(self.ptr) };
108        f(val)
109    }
110}
111
112impl<'a, T, R> Symbol<'a, extern "C" fn(T) -> R> {
113    /// Calls this symbol if this symbol is a function.
114    ///
115    /// # Arguments
116    ///
117    /// * `val`: argument #1.
118    ///
119    /// returns: R
120    pub fn call(&self, val: T) -> R {
121        let f: extern "C" fn(T) -> R = unsafe { std::mem::transmute(self.ptr) };
122        f(val)
123    }
124}
125
126impl<'a, T, T1, R> Symbol<'a, extern "C" fn(T, T1) -> R> {
127    /// Calls this symbol if this symbol is a function.
128    ///
129    /// # Arguments
130    ///
131    /// * `val`: argument #1.
132    ///
133    /// returns: R
134    pub fn call(&self, val: T, val1: T1) -> R {
135        let f: extern "C" fn(T, T1) -> R = unsafe { std::mem::transmute(self.ptr) };
136        f(val, val1)
137    }
138}
139
140impl<'a, T, T1, T2, R> Symbol<'a, extern "C" fn(T, T1, T2) -> R> {
141    /// Calls this symbol if this symbol is a function.
142    ///
143    /// # Arguments
144    ///
145    /// * `val`: argument #1.
146    ///
147    /// returns: R
148    pub fn call(&self, val: T, val1: T1, val2: T2) -> R {
149        let f: extern "C" fn(T, T1, T2) -> R = unsafe { std::mem::transmute(self.ptr) };
150        f(val, val1, val2)
151    }
152}
153
154impl<'a, R> Symbol<'a, extern "C" fn() -> R> {
155    /// Calls this symbol if this symbol is a function.
156    ///
157    /// returns: R
158    pub fn call(&self) -> R {
159        let f: extern "C" fn() -> R = unsafe { std::mem::transmute(self.ptr) };
160        f()
161    }
162}