sourceafIoc::InjectionCtx.fan


** Passed to [DependencyProviders]`DependencyProvider` to give contextual injection information.
@Js
mixin InjectionCtx {
    
    ** The id of the service (if any) that is being created. 
    abstract Str?       serviceId()

    ** The object that will receive the injection.
    abstract Obj?       targetInstance()
    
    ** The 'Type' of object that will receive the injection. 
    ** This is the parent 'Type' that contains the field or method.
    ** Is 'null' when resolving parameters for a pure / non-method func.
    abstract Type?      targetType()

    ** The field to be injected. Only available for field injection. 
    abstract Field?     field()

    ** The method to be injected. Only available for some func injection.
    ** 
    ** Convenience for 'func?.method'. 
    Method? method()    { func?.method }

    ** The func to be injected. Only available for func injection. 
    abstract Func?      func()

    ** Provided arguments to call the func with. 
    abstract Obj?[]?    funcArgs()
    
    ** The func 'Param' to be injected. Only available for func injection. 
    abstract Param?     funcParam()

    ** The index of the func 'Param' to be injected. Only available for func injection. 
    abstract Int?       funcParamIndex()

    ** Returns 'true' if performing field injection.
    Bool isFieldInjection() {
        field != null 
    }

    ** Returns 'true' if performing func (or method) injection.
    ** 
    ** Convenience for 'func != null'. 
    Bool isFuncInjection() {
        func != null 
    }

    ** Returns 'true' if performing method injection.
    ** 
    ** Convenience for 'func != null && func.method != null'. 
    Bool isMethodInjection() {
        func != null && func.method != null
    }

    ** Returns 'true' if the first parameter of the func should be a 'Map' or 'List' service configuration.
    virtual Bool funcTakesServiceConfig() {
        serviceId != null &&
        func != null && method != null &&
        (method.isCtor || method.hasFacet(Build#) || method.hasFacet(Override#)) &&
        (method.params.first?.type?.name == "List" || method.params.first?.type?.name == "Map")
    }

    ** Returns the index into 'funcArgs' should it be applicable, 'null' otherwise. 
    ** This takes into account any service configuration injection (if applicable).
    Int? funcArgIndex() {
        if (!isFuncInjection || funcArgs == null)
            return null
        if (funcTakesServiceConfig && funcParamIndex == 0)
            return null
        funcArgIndex := funcTakesServiceConfig ? funcParamIndex - 1 : funcParamIndex
        return funcArgIndex >= funcArgs.size ? null : funcArgIndex
    }

    ** Returns 'true' if injecting a 'Map' or 'List' service configuration.
    Bool isFuncArgServiceConfig() {
        funcTakesServiceConfig && funcParamIndex == 0
    }

    ** Returns 'true' if an argument has been provided for this func parameter injection.
    Bool isFuncArgProvided() {
        funcArgIndex != null
    }

    ** Returns 'true' if injecting a ctor it-block
    Bool isFuncArgItBlock() {
        func != null && method != null &&
        method.isCtor &&
        funcParamIndex == func.params.size - 1 &&
        funcParam.type.toNonNullable.fits(|This|#)      
    }

    ** Returns 'true' if the func argument has been reserved by system providers; namely if the parameter is:
    **  - service configuration
    **  - a provider func argument
    **  - a ctor it-block 
    Bool isFuncArgReserved() {
        isFuncArgServiceConfig || isFuncArgProvided || isFuncArgItBlock
    }
    
    @NoDoc
    override Str toStr() {
        if (isFieldInjection)
            return "Field Injection: ${field.qname}"
        if (isMethodInjection)
            return "Method Injection: ${funcParam.type.qname} into ${method.qname}"
        if (isFuncInjection)
            return "Func Injection: ${funcParam.type.qname} into ${func.typeof.signature}"
        return "Unknown Injection"
    }
}

@Js
internal class InjectionCtxImpl : InjectionCtx {
    
    override Str?       serviceId
    override Obj?       targetInstance
    override Type?      targetType
    override Field?     field
    override Func?      func
    override Obj?[]?    funcArgs
    override Param?     funcParam
    override Int?       funcParamIndex
    override Bool       funcTakesServiceConfig

    @NoDoc
    new make(|This|? in := null) {
        in?.call(this)
        
        funcTakesServiceConfig = 
            serviceId != null &&
            func != null && method != null &&
            (method.isCtor || method.hasFacet(Build#) || method.hasFacet(Override#)) &&
            (method.params.first?.type?.name == "List" || method.params.first?.type?.name == "Map")
    }
}