//
//  Target.m
//  MYUtilities
//
//  Created by Jens Alfke on 2/11/08.
//  Copyright 2008 Jens Alfke. All rights reserved.
//

#import "Target.h"


NSInvocation* _mktarget( id rcvr, SEL action )
{
    NSMethodSignature *sig = [rcvr methodSignatureForSelector: action];
    CAssert(sig,@"%@<%p> does not respond to %@",[rcvr class],rcvr,NSStringFromSelector(action));
    CAssert(sig.numberOfArguments==3,
           @"-[%@ %@] can't be used as a target because it takes >1 param",
           [rcvr class],NSStringFromSelector(action));
    CAssert(0==strcmp([sig getArgumentTypeAtIndex: 2],"@"),
           @"-[%@ %@] can't be used as a target because it takes a non-object param",
           [rcvr class],NSStringFromSelector(action));
    NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sig];
    inv.target = rcvr;
    inv.selector = action;
    return inv;
}


id $calltarget( NSInvocation *target, id param )
{
    id result = nil;
    if( target && target.target ) {
        [target retain];
        @try{
            [target setArgument: &param atIndex: 2];
            [target invoke];
            
            NSMethodSignature *sig = target.methodSignature;
            NSUInteger returnLength = sig.methodReturnLength;
            if( returnLength==0 ) {
                result = nil; // void
            } else {
                const char *returnType = sig.methodReturnType;
                if( returnType[0]=='@' ) {
                    [target getReturnValue: &result];
                } else {
                    UInt8 returnBuffer[returnLength];
                    [target getReturnValue: &returnBuffer];
                    result = [NSValue valueWithBytes: &returnBuffer objCType: returnType];
                }
            }
        }@finally{
            [target release];
        }
    }
    return result;
}
