abi_stable/library/root_mod_trait.rs
1use super::*;
2
3use crate::{prefix_type::PrefixRefTrait, utils::leak_value};
4
5/// The root module of a dynamic library,
6/// which may contain other modules,function pointers,and static references.
7///
8///
9/// # Examples
10///
11/// For a more in-context example of a type implementing this trait you can look
12/// at either the example in the readme for this crate,
13/// or the `example/example_*_interface` crates in this crates' repository .
14///
15/// ### Basic
16///
17/// ```rust
18/// use abi_stable::{library::RootModule, sabi_types::VersionStrings, StableAbi};
19///
20/// #[repr(C)]
21/// #[derive(StableAbi)]
22/// #[sabi(kind(Prefix(prefix_ref = Module_Ref, prefix_fields = Module_Prefix)))]
23/// pub struct Module {
24/// pub first: u8,
25/// // The `#[sabi(last_prefix_field)]` attribute here means that this is
26/// // the last field in this module that was defined in the
27/// // first compatible version of the library,
28/// #[sabi(last_prefix_field)]
29/// pub second: u16,
30/// pub third: u32,
31/// }
32/// impl RootModule for Module_Ref {
33/// abi_stable::declare_root_module_statics! {Module_Ref}
34/// const BASE_NAME: &'static str = "example_root_module";
35/// const NAME: &'static str = "example_root_module";
36/// const VERSION_STRINGS: VersionStrings = abi_stable::package_version_strings!();
37/// }
38///
39
40/// # fn main(){}
41/// ```
42pub trait RootModule: Sized + StableAbi + PrefixRefTrait + 'static {
43 /// The name of the dynamic library,which is the same on all platforms.
44 /// This is generally the name of the `implementation crate`.
45 const BASE_NAME: &'static str;
46
47 /// The name of the library used in error messages.
48 const NAME: &'static str;
49
50 /// The version number of the library that this is a root module of.
51 ///
52 /// Initialize this with
53 /// [`package_version_strings!()`](../macro.package_version_strings.html)
54 const VERSION_STRINGS: VersionStrings;
55
56 /// All the constants of this trait and supertraits.
57 ///
58 /// It can safely be used as a proxy for the associated constants of this trait.
59 const CONSTANTS: RootModuleConsts = RootModuleConsts {
60 base_name: RStr::from_str(Self::BASE_NAME),
61 name: RStr::from_str(Self::NAME),
62 version_strings: Self::VERSION_STRINGS,
63 layout: IsLayoutChecked::Yes(<Self as StableAbi>::LAYOUT),
64 c_abi_testing_fns: crate::library::c_abi_testing::C_ABI_TESTING_FNS,
65 _priv: (),
66 };
67
68 /// Like `Self::CONSTANTS`,
69 /// except without including the type layout constant for the root module.
70 const CONSTANTS_NO_ABI_INFO: RootModuleConsts = RootModuleConsts {
71 layout: IsLayoutChecked::No,
72 ..Self::CONSTANTS
73 };
74
75 /// Gets the statics for Self.
76 ///
77 /// To define this associated function use:
78 /// [`abi_stable::declare_root_module_statics!{TypeOfSelf}`
79 /// ](../macro.declare_root_module_statics.html).
80 /// Passing `Self` instead of `TypeOfSelf` won't work.
81 ///
82 fn root_module_statics() -> &'static RootModuleStatics<Self>;
83
84 /// Gets the root module,returning None if the module is not yet loaded.
85 #[inline]
86 fn get_module() -> Option<Self> {
87 Self::root_module_statics().root_mod.get()
88 }
89
90 /// Gets the RawLibrary of the module,
91 /// returning None if the dynamic library failed to load
92 /// (it doesn't exist or layout checking failed).
93 ///
94 /// Note that if the root module is initialized using `Self::load_module_with`,
95 /// this will return None even though `Self::get_module` does not.
96 ///
97 #[inline]
98 fn get_raw_library() -> Option<&'static RawLibrary> {
99 Self::root_module_statics().raw_lib.get()
100 }
101
102 /// Returns the path the library would be loaded from,given a directory(folder).
103 fn get_library_path(directory: &Path) -> PathBuf {
104 let base_name = Self::BASE_NAME;
105 RawLibrary::path_in_directory(directory, base_name, LibrarySuffix::NoSuffix)
106 }
107
108 /// Loads the root module,with a closure which either
109 /// returns the root module or an error.
110 ///
111 /// If the root module was already loaded,
112 /// this will return the already loaded root module,
113 /// without calling the closure.
114 fn load_module_with<F, E>(f: F) -> Result<Self, E>
115 where
116 F: FnOnce() -> Result<Self, E>,
117 {
118 Self::root_module_statics().root_mod.try_init(f)
119 }
120
121 /// Loads this module from the path specified by `where_`,
122 /// first loading the dynamic library if it wasn't already loaded.
123 ///
124 /// Once the root module is loaded,
125 /// this will return the already loaded root module.
126 ///
127 /// # Warning
128 ///
129 /// If this function is called within a dynamic library,
130 /// it must be called either within the root module loader function or
131 /// after that function has been called.
132 ///
133 /// **DO NOT** call this in the static initializer of a dynamic library,
134 /// since this library relies on setting up its global state before
135 /// calling the root module loader.
136 ///
137 /// # Errors
138 ///
139 /// This will return these errors:
140 ///
141 /// - `LibraryError::OpenError`:
142 /// If the dynamic library itself could not be loaded.
143 ///
144 /// - `LibraryError::GetSymbolError`:
145 /// If the root module was not exported.
146 ///
147 /// - `LibraryError::InvalidAbiHeader`:
148 /// If the abi_stable version used by the library is not compatible.
149 ///
150 /// - `LibraryError::ParseVersionError`:
151 /// If the version strings in the library can't be parsed as version numbers,
152 /// this can only happen if the version strings are manually constructed.
153 ///
154 /// - `LibraryError::IncompatibleVersionNumber`:
155 /// If the version number of the library is incompatible.
156 ///
157 /// - `LibraryError::AbiInstability`:
158 /// If the layout of the root module is not the expected one.
159 ///
160 /// - `LibraryError::RootModule` :
161 /// If the root module initializer returned an error or panicked.
162 ///
163 fn load_from(where_: LibraryPath<'_>) -> Result<Self, LibraryError> {
164 let statics = Self::root_module_statics();
165 statics.root_mod.try_init(|| {
166 let lib = statics.raw_lib.try_init(|| -> Result<_, LibraryError> {
167 let raw_library = load_raw_library::<Self>(where_)?;
168
169 // if the library isn't leaked
170 // it would cause any use of the module to be a use after free.
171 //
172 // By leaking the library
173 // this allows the root module loader to do anything that'd prevent
174 // sound library unloading.
175 Ok(leak_value(raw_library))
176 })?;
177 let items = unsafe { lib_header_from_raw_library(lib)? };
178
179 items.ensure_layout::<Self>()?;
180
181 // safety: the layout was checked in the code above,
182 unsafe {
183 items
184 .init_root_module_with_unchecked_layout::<Self>()?
185 .initialization()
186 }
187 })
188 }
189
190 /// Loads this module from the directory specified by `where_`,
191 /// first loading the dynamic library if it wasn't already loaded.
192 ///
193 /// Once the root module is loaded,
194 /// this will return the already loaded root module.
195 ///
196 /// Warnings and Errors are detailed in [`load_from`](#method.load_from),
197 ///
198 fn load_from_directory(where_: &Path) -> Result<Self, LibraryError> {
199 Self::load_from(LibraryPath::Directory(where_))
200 }
201
202 /// Loads this module from the file at `path_`,
203 /// first loading the dynamic library if it wasn't already loaded.
204 ///
205 /// Once the root module is loaded,
206 /// this will return the already loaded root module.
207 ///
208 /// Warnings and Errors are detailed in [`load_from`](#method.load_from),
209 ///
210 fn load_from_file(path_: &Path) -> Result<Self, LibraryError> {
211 Self::load_from(LibraryPath::FullPath(path_))
212 }
213
214 /// Defines behavior that happens once the module is loaded.
215 ///
216 /// This is ran in the `RootModule::load*` associated functions
217 /// after the root module has succesfully been loaded.
218 ///
219 /// The default implementation does nothing.
220 fn initialization(self) -> Result<Self, LibraryError> {
221 Ok(self)
222 }
223}
224
225/// Loads the raw library at `where_`
226fn load_raw_library<M>(where_: LibraryPath<'_>) -> Result<RawLibrary, LibraryError>
227where
228 M: RootModule,
229{
230 let path = match where_ {
231 LibraryPath::Directory(directory) => M::get_library_path(directory),
232 LibraryPath::FullPath(full_path) => full_path.to_owned(),
233 };
234 RawLibrary::load_at(&path)
235}
236
237/// Gets the LibHeader of a library.
238///
239/// # Errors
240///
241/// This will return these errors:
242///
243/// - `LibraryError::GetSymbolError`:
244/// If the root module was not exported.
245///
246/// - `LibraryError::InvalidAbiHeader`:
247/// If the abi_stable used by the library is not compatible.
248///
249/// # Safety
250///
251/// The LibHeader is implicitly tied to the lifetime of the library,
252/// it will contain dangling `'static` references if the library is dropped before it does.
253///
254///
255pub unsafe fn lib_header_from_raw_library(
256 raw_library: &RawLibrary,
257) -> Result<&'static LibHeader, LibraryError> {
258 unsafe { abi_header_from_raw_library(raw_library)?.upgrade() }
259}
260
261/// Gets the AbiHeaderRef of a library.
262///
263/// # Errors
264///
265/// This will return these errors:
266///
267/// - `LibraryError::GetSymbolError`:
268/// If the root module was not exported.
269///
270/// # Safety
271///
272/// The AbiHeaderRef is implicitly tied to the lifetime of the library,
273/// it will contain dangling `'static` references if the library is dropped before it does.
274///
275///
276pub unsafe fn abi_header_from_raw_library(
277 raw_library: &RawLibrary,
278) -> Result<AbiHeaderRef, LibraryError> {
279 let mangled = ROOT_MODULE_LOADER_NAME_WITH_NUL;
280 let header: AbiHeaderRef = unsafe { *raw_library.get::<AbiHeaderRef>(mangled.as_bytes())? };
281
282 Ok(header)
283}
284
285/// Gets the LibHeader of the library at the path.
286///
287/// This leaks the underlying dynamic library,
288/// if you need to do this without leaking you'll need to use
289/// `lib_header_from_raw_library` instead.
290///
291/// # Errors
292///
293/// This will return these errors:
294///
295/// - `LibraryError::OpenError`:
296/// If the dynamic library itself could not be loaded.
297///
298/// - `LibraryError::GetSymbolError`:
299/// If the root module was not exported.
300///
301/// - `LibraryError::InvalidAbiHeader`:
302/// If the abi_stable version used by the library is not compatible.
303///
304///
305pub fn lib_header_from_path(path: &Path) -> Result<&'static LibHeader, LibraryError> {
306 let raw_lib = RawLibrary::load_at(path)?;
307
308 let library_getter = unsafe { lib_header_from_raw_library(&raw_lib)? };
309
310 mem::forget(raw_lib);
311
312 Ok(library_getter)
313}
314
315/// Gets the AbiHeaderRef of the library at the path.
316///
317/// This leaks the underlying dynamic library,
318/// if you need to do this without leaking you'll need to use
319/// `lib_header_from_raw_library` instead.
320///
321/// # Errors
322///
323/// This will return these errors:
324///
325/// - `LibraryError::OpenError`:
326/// If the dynamic library itself could not be loaded.
327///
328/// - `LibraryError::GetSymbolError`:
329/// If the root module was not exported.
330///
331///
332pub fn abi_header_from_path(path: &Path) -> Result<AbiHeaderRef, LibraryError> {
333 let raw_lib = RawLibrary::load_at(path)?;
334
335 let library_getter = unsafe { abi_header_from_raw_library(&raw_lib)? };
336
337 mem::forget(raw_lib);
338
339 Ok(library_getter)
340}
341
342//////////////////////////////////////////////////////////////////////
343
344macro_rules! declare_root_module_consts {
345 (
346 fields=[
347 $(
348 $(#[$field_meta:meta])*
349 method_docs=$method_docs:expr,
350 $field:ident : $field_ty:ty
351 ),* $(,)*
352 ]
353 ) => (
354 /// All the constants of the [`RootModule`] trait for some erased type.
355 ///
356 /// [`RootModule`]: ./trait.RootModule.html
357 #[repr(C)]
358 #[derive(StableAbi,Copy,Clone)]
359 pub struct RootModuleConsts{
360 $(
361 $(#[$field_meta])*
362 $field : $field_ty,
363 )*
364 _priv:(),
365 }
366
367 impl RootModuleConsts{
368 $(
369 #[doc=$method_docs]
370 pub const fn $field(&self)->$field_ty{
371 self.$field
372 }
373 )*
374 }
375
376 )
377}
378
379declare_root_module_consts! {
380 fields=[
381 method_docs="
382 The name of the dynamic library,which is the same on all platforms.
383 This is generally the name of the implementation crate.",
384 base_name: RStr<'static>,
385
386 method_docs="The name of the library used in error messages.",
387 name: RStr<'static>,
388
389 method_docs="The version number of the library this was created from.",
390 version_strings: VersionStrings,
391
392 method_docs="The (optional) type layout constant of the root module.",
393 layout: IsLayoutChecked,
394
395 method_docs="\
396 Functions used to test that the C abi is the same in both the library
397 and the loader\
398 ",
399 c_abi_testing_fns:&'static CAbiTestingFns,
400 ]
401}