use core::any::type_name;
use crate::ffi::FfiResult::{FfiErr, FfiOk};
use crate::{
ffi::FfiUsizeIterator,
resolvable::SealedResolvable,
strategy::{Identifyable, Strategy},
untyped::{AutoFreePointer, UntypedFn},
AliasBuilder, AnyPtr, GenericServiceCollection, InternalBuildResult, Resolvable,
ServiceProducer, ServiceProvider, UntypedFnFactory, UntypedFnFactoryContext,
};
pub trait Registrar<TS: Strategy> {
type Item;
fn register(
self,
collection: &mut GenericServiceCollection<TS>,
) -> AliasBuilder<'_, Self::Item, TS>;
}
impl<TS: Strategy, T: Identifyable<TS::Id>> Registrar<TS> for fn() -> T {
type Item = T;
fn register(
self,
collection: &mut GenericServiceCollection<TS>,
) -> AliasBuilder<'_, Self::Item, TS> {
extern "C" fn factory<T: Identifyable<TS::Id>, TS: Strategy + 'static>(
stage_1_data: AutoFreePointer,
_ctx: &mut UntypedFnFactoryContext<TS>,
) -> InternalBuildResult<TS> {
extern "C" fn func<T: Identifyable<TS::Id>, TS: Strategy + 'static>(
_: *const ServiceProvider<TS>,
stage_2_data: *const AutoFreePointer,
) -> T {
let stage_2_data = unsafe { &*stage_2_data as &AutoFreePointer };
let ptr = stage_2_data.get_pointer();
let creator: fn() -> T = unsafe { core::mem::transmute(ptr) };
creator()
}
FfiOk(UntypedFn::create(func::<T, TS>, stage_1_data))
}
let factory = UntypedFnFactory::no_alloc(self as AnyPtr, factory::<T, TS>);
collection
.producer_factories
.push(ServiceProducer::<TS>::new::<T>(factory));
AliasBuilder::new(collection)
}
}
impl<TS: Strategy + 'static, T: Identifyable<TS::Id>, TDep: Resolvable<TS> + 'static> Registrar<TS>
for fn(TDep) -> T
{
type Item = T;
fn register(
self,
collection: &mut GenericServiceCollection<TS>,
) -> AliasBuilder<'_, Self::Item, TS> {
type InnerContext<TDep, TS> = (<TDep as SealedResolvable<TS>>::PrecheckResult, AnyPtr);
extern "C" fn factory<
T: Identifyable<TS::Id>,
TDep: Resolvable<TS> + 'static,
TS: Strategy + 'static,
>(
outer_ctx: AutoFreePointer, ctx: &mut UntypedFnFactoryContext<TS>,
) -> InternalBuildResult<TS> {
let key = match TDep::precheck(ctx.final_ordered_types) {
Ok(x) => x,
Err(x) => return FfiErr(x.with_dependee::<T>()),
};
let data = TDep::iter_positions(ctx.final_ordered_types);
ctx.cyclic_reference_candidates.insert(
type_name::<TDep::ItemPreChecked>().into(),
FfiUsizeIterator::from_iter(data),
);
extern "C" fn func<
T: Identifyable<TS::Id>,
TDep: Resolvable<TS> + 'static,
TS: Strategy + 'static,
>(
provider: *const ServiceProvider<TS>,
outer_ctx: *const AutoFreePointer,
) -> T {
let provider = unsafe { &*provider as &ServiceProvider<TS> };
let outer_ctx = unsafe { &*outer_ctx as &AutoFreePointer };
let (key, c): &InnerContext<TDep, TS> =
unsafe { &*(outer_ctx.get_pointer() as *const InnerContext<TDep, TS>) };
let creator: fn(TDep) -> T = unsafe { core::mem::transmute(*c) };
let arg = TDep::resolve_prechecked_self(provider, key);
creator(arg)
}
let inner: InnerContext<TDep, TS> = (key, outer_ctx.get_pointer());
FfiOk(UntypedFn::create(
func::<T, TDep, TS>,
AutoFreePointer::boxed(inner),
))
}
let factory = UntypedFnFactory::no_alloc(self as AnyPtr, factory::<T, TDep, TS>);
collection
.producer_factories
.push(ServiceProducer::<TS>::new::<T>(factory));
AliasBuilder::new(collection)
}
}