use super::*;
use crate::{prefix_type::PrefixRefTrait, utils::leak_value};
pub trait RootModule: Sized + StableAbi + PrefixRefTrait + 'static {
const BASE_NAME: &'static str;
const NAME: &'static str;
const VERSION_STRINGS: VersionStrings;
const CONSTANTS: RootModuleConsts = RootModuleConsts {
base_name: RStr::from_str(Self::BASE_NAME),
name: RStr::from_str(Self::NAME),
version_strings: Self::VERSION_STRINGS,
layout: IsLayoutChecked::Yes(<Self as StableAbi>::LAYOUT),
c_abi_testing_fns: crate::library::c_abi_testing::C_ABI_TESTING_FNS,
_priv: (),
};
const CONSTANTS_NO_ABI_INFO: RootModuleConsts = RootModuleConsts {
layout: IsLayoutChecked::No,
..Self::CONSTANTS
};
fn root_module_statics() -> &'static RootModuleStatics<Self>;
#[inline]
fn get_module() -> Option<Self> {
Self::root_module_statics().root_mod.get()
}
#[inline]
fn get_raw_library() -> Option<&'static RawLibrary> {
Self::root_module_statics().raw_lib.get()
}
fn get_library_path(directory: &Path) -> PathBuf {
let base_name = Self::BASE_NAME;
RawLibrary::path_in_directory(directory, base_name, LibrarySuffix::NoSuffix)
}
fn load_module_with<F, E>(f: F) -> Result<Self, E>
where
F: FnOnce() -> Result<Self, E>,
{
Self::root_module_statics().root_mod.try_init(f)
}
fn load_from(where_: LibraryPath<'_>) -> Result<Self, LibraryError> {
let statics = Self::root_module_statics();
statics.root_mod.try_init(|| {
let lib = statics.raw_lib.try_init(|| -> Result<_, LibraryError> {
let raw_library = load_raw_library::<Self>(where_)?;
Ok(leak_value(raw_library))
})?;
let items = unsafe { lib_header_from_raw_library(lib)? };
items.ensure_layout::<Self>()?;
unsafe {
items
.init_root_module_with_unchecked_layout::<Self>()?
.initialization()
}
})
}
fn load_from_directory(where_: &Path) -> Result<Self, LibraryError> {
Self::load_from(LibraryPath::Directory(where_))
}
fn load_from_file(path_: &Path) -> Result<Self, LibraryError> {
Self::load_from(LibraryPath::FullPath(path_))
}
fn initialization(self) -> Result<Self, LibraryError> {
Ok(self)
}
}
fn load_raw_library<M>(where_: LibraryPath<'_>) -> Result<RawLibrary, LibraryError>
where
M: RootModule,
{
let path = match where_ {
LibraryPath::Directory(directory) => M::get_library_path(directory),
LibraryPath::FullPath(full_path) => full_path.to_owned(),
};
RawLibrary::load_at(&path)
}
pub unsafe fn lib_header_from_raw_library(
raw_library: &RawLibrary,
) -> Result<&'static LibHeader, LibraryError> {
unsafe { abi_header_from_raw_library(raw_library)?.upgrade() }
}
pub unsafe fn abi_header_from_raw_library(
raw_library: &RawLibrary,
) -> Result<AbiHeaderRef, LibraryError> {
let mangled = ROOT_MODULE_LOADER_NAME_WITH_NUL;
let header: AbiHeaderRef = unsafe { *raw_library.get::<AbiHeaderRef>(mangled.as_bytes())? };
Ok(header)
}
pub fn lib_header_from_path(path: &Path) -> Result<&'static LibHeader, LibraryError> {
let raw_lib = RawLibrary::load_at(path)?;
let library_getter = unsafe { lib_header_from_raw_library(&raw_lib)? };
mem::forget(raw_lib);
Ok(library_getter)
}
pub fn abi_header_from_path(path: &Path) -> Result<AbiHeaderRef, LibraryError> {
let raw_lib = RawLibrary::load_at(path)?;
let library_getter = unsafe { abi_header_from_raw_library(&raw_lib)? };
mem::forget(raw_lib);
Ok(library_getter)
}
macro_rules! declare_root_module_consts {
(
fields=[
$(
$(#[$field_meta:meta])*
method_docs=$method_docs:expr,
$field:ident : $field_ty:ty
),* $(,)*
]
) => (
/// All the constants of the [`RootModule`] trait for some erased type.
///
/// [`RootModule`]: ./trait.RootModule.html
#[repr(C)]
#[derive(StableAbi,Copy,Clone)]
pub struct RootModuleConsts{
$(
$(#[$field_meta])*
$field : $field_ty,
)*
_priv:(),
}
impl RootModuleConsts{
$(
#[doc=$method_docs]
pub const fn $field(&self)->$field_ty{
self.$field
}
)*
}
)
}
declare_root_module_consts! {
fields=[
method_docs="
The name of the dynamic library,which is the same on all platforms.
This is generally the name of the implementation crate.",
base_name: RStr<'static>,
method_docs="The name of the library used in error messages.",
name: RStr<'static>,
method_docs="The version number of the library this was created from.",
version_strings: VersionStrings,
method_docs="The (optional) type layout constant of the root module.",
layout: IsLayoutChecked,
method_docs="\
Functions used to test that the C abi is the same in both the library
and the loader\
",
c_abi_testing_fns:&'static CAbiTestingFns,
]
}