use super::Module;
use crate::{
arch::NativeArch,
relocation::RelocationArch,
sync::{Arc, Weak},
tls::TlsResolver,
};
use alloc::{boxed::Box, vec::Vec};
use core::{any::Any, fmt, ops::Deref, slice};
pub struct ModuleHandle<Arch: RelocationArch = NativeArch, Tls: TlsResolver<Arch> = ()> {
module: Arc<dyn Module<Arch, Tls>>,
}
impl<Arch: RelocationArch, Tls: TlsResolver<Arch>> Clone for ModuleHandle<Arch, Tls> {
#[inline]
fn clone(&self) -> Self {
Self {
module: Arc::clone(&self.module),
}
}
}
impl<Arch: RelocationArch, Tls: TlsResolver<Arch> + 'static> ModuleHandle<Arch, Tls> {
#[inline]
pub fn new<M>(module: M) -> Self
where
M: Module<Arch, Tls> + 'static,
{
Self {
module: Arc::from(Box::new(module) as Box<dyn Module<Arch, Tls>>),
}
}
#[inline]
pub fn from_shared(module: Arc<dyn Module<Arch, Tls>>) -> Self {
Self { module }
}
#[inline]
pub fn as_dyn(&self) -> &(dyn Module<Arch, Tls> + 'static) {
&*self.module
}
#[inline]
pub fn downcast_ref<T>(&self) -> Option<&T>
where
T: Module<Arch, Tls> + 'static,
{
let module = self.as_dyn() as &dyn Any;
module
.downcast_ref::<T>()
.or_else(|| module.downcast_ref::<Arc<T>>().map(|module| &**module))
}
#[inline]
pub fn into_inner(self) -> Arc<dyn Module<Arch, Tls>> {
self.module
}
}
impl<Arch: RelocationArch, Tls: TlsResolver<Arch> + 'static> Deref for ModuleHandle<Arch, Tls> {
type Target = dyn Module<Arch, Tls>;
#[inline]
fn deref(&self) -> &Self::Target {
self.as_dyn()
}
}
impl<Arch: RelocationArch, Tls: TlsResolver<Arch> + 'static> AsRef<dyn Module<Arch, Tls>>
for ModuleHandle<Arch, Tls>
{
#[inline]
fn as_ref(&self) -> &(dyn Module<Arch, Tls> + 'static) {
self.as_dyn()
}
}
impl<M, Arch, Tls> From<Arc<M>> for ModuleHandle<Arch, Tls>
where
M: Module<Arch, Tls> + 'static,
Arch: RelocationArch,
Tls: TlsResolver<Arch> + 'static,
{
#[inline]
fn from(module: Arc<M>) -> Self {
Self::new(module)
}
}
impl<Arch: RelocationArch, Tls: TlsResolver<Arch> + 'static> From<Arc<dyn Module<Arch, Tls>>>
for ModuleHandle<Arch, Tls>
{
#[inline]
fn from(module: Arc<dyn Module<Arch, Tls>>) -> Self {
Self::from_shared(module)
}
}
pub struct ModuleScope<Arch: RelocationArch = NativeArch, Tls: TlsResolver<Arch> = ()> {
modules: Arc<[ModuleHandle<Arch, Tls>]>,
}
pub(crate) struct WeakModuleScope<Arch: RelocationArch = NativeArch, Tls: TlsResolver<Arch> = ()> {
modules: Weak<[ModuleHandle<Arch, Tls>]>,
}
pub struct ModuleScopeBuilder<Arch: RelocationArch = NativeArch, Tls: TlsResolver<Arch> = ()> {
modules: Vec<ModuleHandle<Arch, Tls>>,
}
impl<Arch: RelocationArch, Tls: TlsResolver<Arch>> Clone for ModuleScopeBuilder<Arch, Tls> {
#[inline]
fn clone(&self) -> Self {
Self {
modules: self.modules.clone(),
}
}
}
impl<Arch: RelocationArch, Tls: TlsResolver<Arch>> ModuleScopeBuilder<Arch, Tls> {
#[inline]
pub const fn new() -> Self {
Self {
modules: Vec::new(),
}
}
pub(crate) fn replace<I, R>(&mut self, modules: I)
where
I: IntoIterator<Item = R>,
R: Into<ModuleHandle<Arch, Tls>>,
{
self.modules.clear();
self.modules.extend(modules.into_iter().map(Into::into));
}
pub fn extend<I, R>(&mut self, modules: I)
where
I: IntoIterator<Item = R>,
R: Into<ModuleHandle<Arch, Tls>>,
{
self.modules.extend(modules.into_iter().map(Into::into));
}
#[inline]
pub fn into_scope(self) -> ModuleScope<Arch, Tls> {
ModuleScope {
modules: Arc::from(self.modules),
}
}
}
impl<Arch: RelocationArch, Tls: TlsResolver<Arch>> Default for ModuleScopeBuilder<Arch, Tls> {
#[inline]
fn default() -> Self {
Self::new()
}
}
impl<Arch: RelocationArch, Tls: TlsResolver<Arch>> Clone for ModuleScope<Arch, Tls> {
#[inline]
fn clone(&self) -> Self {
Self {
modules: Arc::clone(&self.modules),
}
}
}
impl<Arch, Tls> fmt::Debug for ModuleScope<Arch, Tls>
where
Arch: RelocationArch,
Tls: TlsResolver<Arch>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list()
.entries(self.modules.iter().map(|module| module.name()))
.finish()
}
}
impl<Arch: RelocationArch, Tls: TlsResolver<Arch>> ModuleScope<Arch, Tls> {
#[inline]
pub(crate) fn downgrade(&self) -> WeakModuleScope<Arch, Tls> {
WeakModuleScope {
modules: Arc::downgrade(&self.modules),
}
}
#[inline]
pub fn as_slice(&self) -> &[ModuleHandle<Arch, Tls>] {
&self.modules
}
#[inline]
pub fn iter(&self) -> slice::Iter<'_, ModuleHandle<Arch, Tls>> {
self.modules.iter()
}
#[inline]
pub fn len(&self) -> usize {
self.modules.len()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.modules.is_empty()
}
}
impl<Arch: RelocationArch, Tls: TlsResolver<Arch>> WeakModuleScope<Arch, Tls> {
#[inline]
pub(crate) fn upgrade(&self) -> Option<ModuleScope<Arch, Tls>> {
self.modules
.upgrade()
.map(|modules| ModuleScope { modules })
}
}