use super::*;
use crate::{
marker_type::NonOwningPhantom,
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<Self>=RootModuleConsts{
inner:ErasedRootModuleConsts{
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:(),
},
_priv:NonOwningPhantom::NEW,
};
const CONSTANTS_NO_ABI_INFO:RootModuleConsts<Self>={
let mut consts=Self::CONSTANTS;
consts.inner.layout=IsLayoutChecked::No;
consts
};
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 raw_library=load_raw_library::<Self>(where_)?;
let items = unsafe{ lib_header_from_raw_library(&raw_library)? };
let root_mod=items.init_root_module::<Self>()?.initialization()?;
let raw_lib=leak_value(raw_library);
statics.raw_lib.init(|| raw_lib );
Ok(root_mod)
})
}
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< &'static AbiHeader , LibraryError>
{
unsafe{
let mut mangled=mangled_root_module_loader_name();
mangled.push('\0');
let library_getter=
raw_library.get::<&'static AbiHeader>(mangled.as_bytes())?;
let header:&'static AbiHeader= *library_getter;
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< &'static AbiHeader , 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 `M`,
/// used mostly to construct a `LibHeader` with `LibHeader::from_constructor`.
///
/// This is constructed with [`RootModule::CONSTANTS`].
///
/// [`RootModule`]: ./trait.RootModule.html
/// [`RootModule::CONSTANTS`]: ./trait.RootModule.html#associatedconstant.CONSTANTS
#[repr(C)]
#[derive(StableAbi,Copy,Clone)]
pub struct RootModuleConsts<M>{
inner:ErasedRootModuleConsts,
_priv:NonOwningPhantom<M>,
}
#[repr(C)]
#[derive(StableAbi,Copy,Clone)]
pub struct ErasedRootModuleConsts{
$(
$(#[$field_meta])*
$field : $field_ty,
)*
_priv:(),
}
impl<M> RootModuleConsts<M>{
pub const fn erased(&self)->ErasedRootModuleConsts{
self.inner
}
$(
#[doc=$method_docs]
pub const fn $field(&self)->$field_ty{
self.inner.$field
}
)*
}
impl ErasedRootModuleConsts{
$(
#[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,
]
}