//
|
// NSInvocation+RACTypeParsing.m
|
// ReactiveCocoa
|
//
|
// Created by Josh Abernathy on 11/17/12.
|
// Copyright (c) 2012 GitHub, Inc. All rights reserved.
|
//
|
|
#import "NSInvocation+RACTypeParsing.h"
|
#import "RACTuple.h"
|
#import "RACUnit.h"
|
#import <CoreGraphics/CoreGraphics.h>
|
|
@implementation NSInvocation (RACTypeParsing)
|
|
- (void)rac_setArgument:(id)object atIndex:(NSUInteger)index {
|
#define PULL_AND_SET(type, selector) \
|
do { \
|
type val = [object selector]; \
|
[self setArgument:&val atIndex:(NSInteger)index]; \
|
} while (0)
|
|
const char *argType = [self.methodSignature getArgumentTypeAtIndex:index];
|
// Skip const type qualifier.
|
if (argType[0] == 'r') {
|
argType++;
|
}
|
|
if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0) {
|
[self setArgument:&object atIndex:(NSInteger)index];
|
} else if (strcmp(argType, @encode(char)) == 0) {
|
PULL_AND_SET(char, charValue);
|
} else if (strcmp(argType, @encode(int)) == 0) {
|
PULL_AND_SET(int, intValue);
|
} else if (strcmp(argType, @encode(short)) == 0) {
|
PULL_AND_SET(short, shortValue);
|
} else if (strcmp(argType, @encode(long)) == 0) {
|
PULL_AND_SET(long, longValue);
|
} else if (strcmp(argType, @encode(long long)) == 0) {
|
PULL_AND_SET(long long, longLongValue);
|
} else if (strcmp(argType, @encode(unsigned char)) == 0) {
|
PULL_AND_SET(unsigned char, unsignedCharValue);
|
} else if (strcmp(argType, @encode(unsigned int)) == 0) {
|
PULL_AND_SET(unsigned int, unsignedIntValue);
|
} else if (strcmp(argType, @encode(unsigned short)) == 0) {
|
PULL_AND_SET(unsigned short, unsignedShortValue);
|
} else if (strcmp(argType, @encode(unsigned long)) == 0) {
|
PULL_AND_SET(unsigned long, unsignedLongValue);
|
} else if (strcmp(argType, @encode(unsigned long long)) == 0) {
|
PULL_AND_SET(unsigned long long, unsignedLongLongValue);
|
} else if (strcmp(argType, @encode(float)) == 0) {
|
PULL_AND_SET(float, floatValue);
|
} else if (strcmp(argType, @encode(double)) == 0) {
|
PULL_AND_SET(double, doubleValue);
|
} else if (strcmp(argType, @encode(BOOL)) == 0) {
|
PULL_AND_SET(BOOL, boolValue);
|
} else if (strcmp(argType, @encode(char *)) == 0) {
|
const char *cString = [object UTF8String];
|
[self setArgument:&cString atIndex:(NSInteger)index];
|
[self retainArguments];
|
} else if (strcmp(argType, @encode(void (^)(void))) == 0) {
|
[self setArgument:&object atIndex:(NSInteger)index];
|
} else {
|
NSCParameterAssert([object isKindOfClass:NSValue.class]);
|
|
NSUInteger valueSize = 0;
|
NSGetSizeAndAlignment([object objCType], &valueSize, NULL);
|
|
#if DEBUG
|
NSUInteger argSize = 0;
|
NSGetSizeAndAlignment(argType, &argSize, NULL);
|
NSCAssert(valueSize == argSize, @"Value size does not match argument size in -rac_setArgument: %@ atIndex: %lu", object, (unsigned long)index);
|
#endif
|
|
unsigned char valueBytes[valueSize];
|
[object getValue:valueBytes];
|
|
[self setArgument:valueBytes atIndex:(NSInteger)index];
|
}
|
|
#undef PULL_AND_SET
|
}
|
|
- (id)rac_argumentAtIndex:(NSUInteger)index {
|
#define WRAP_AND_RETURN(type) \
|
do { \
|
type val = 0; \
|
[self getArgument:&val atIndex:(NSInteger)index]; \
|
return @(val); \
|
} while (0)
|
|
const char *argType = [self.methodSignature getArgumentTypeAtIndex:index];
|
// Skip const type qualifier.
|
if (argType[0] == 'r') {
|
argType++;
|
}
|
|
if (strcmp(argType, @encode(id)) == 0 || strcmp(argType, @encode(Class)) == 0) {
|
__autoreleasing id returnObj;
|
[self getArgument:&returnObj atIndex:(NSInteger)index];
|
return returnObj;
|
} else if (strcmp(argType, @encode(char)) == 0) {
|
WRAP_AND_RETURN(char);
|
} else if (strcmp(argType, @encode(int)) == 0) {
|
WRAP_AND_RETURN(int);
|
} else if (strcmp(argType, @encode(short)) == 0) {
|
WRAP_AND_RETURN(short);
|
} else if (strcmp(argType, @encode(long)) == 0) {
|
WRAP_AND_RETURN(long);
|
} else if (strcmp(argType, @encode(long long)) == 0) {
|
WRAP_AND_RETURN(long long);
|
} else if (strcmp(argType, @encode(unsigned char)) == 0) {
|
WRAP_AND_RETURN(unsigned char);
|
} else if (strcmp(argType, @encode(unsigned int)) == 0) {
|
WRAP_AND_RETURN(unsigned int);
|
} else if (strcmp(argType, @encode(unsigned short)) == 0) {
|
WRAP_AND_RETURN(unsigned short);
|
} else if (strcmp(argType, @encode(unsigned long)) == 0) {
|
WRAP_AND_RETURN(unsigned long);
|
} else if (strcmp(argType, @encode(unsigned long long)) == 0) {
|
WRAP_AND_RETURN(unsigned long long);
|
} else if (strcmp(argType, @encode(float)) == 0) {
|
WRAP_AND_RETURN(float);
|
} else if (strcmp(argType, @encode(double)) == 0) {
|
WRAP_AND_RETURN(double);
|
} else if (strcmp(argType, @encode(BOOL)) == 0) {
|
WRAP_AND_RETURN(BOOL);
|
} else if (strcmp(argType, @encode(char *)) == 0) {
|
WRAP_AND_RETURN(const char *);
|
} else if (strcmp(argType, @encode(void (^)(void))) == 0) {
|
__unsafe_unretained id block = nil;
|
[self getArgument:&block atIndex:(NSInteger)index];
|
return [block copy];
|
} else {
|
NSUInteger valueSize = 0;
|
NSGetSizeAndAlignment(argType, &valueSize, NULL);
|
|
unsigned char valueBytes[valueSize];
|
[self getArgument:valueBytes atIndex:(NSInteger)index];
|
|
return [NSValue valueWithBytes:valueBytes objCType:argType];
|
}
|
|
return nil;
|
|
#undef WRAP_AND_RETURN
|
}
|
|
- (RACTuple *)rac_argumentsTuple {
|
NSUInteger numberOfArguments = self.methodSignature.numberOfArguments;
|
NSMutableArray *argumentsArray = [NSMutableArray arrayWithCapacity:numberOfArguments - 2];
|
for (NSUInteger index = 2; index < numberOfArguments; index++) {
|
[argumentsArray addObject:[self rac_argumentAtIndex:index] ?: RACTupleNil.tupleNil];
|
}
|
|
return [RACTuple tupleWithObjectsFromArray:argumentsArray];
|
}
|
|
- (void)setRac_argumentsTuple:(RACTuple *)arguments {
|
NSCAssert(arguments.count == self.methodSignature.numberOfArguments - 2, @"Number of supplied arguments (%lu), does not match the number expected by the signature (%lu)", (unsigned long)arguments.count, (unsigned long)self.methodSignature.numberOfArguments - 2);
|
|
NSUInteger index = 2;
|
for (id arg in arguments) {
|
[self rac_setArgument:(arg == RACTupleNil.tupleNil ? nil : arg) atIndex:index];
|
index++;
|
}
|
}
|
|
- (id)rac_returnValue {
|
#define WRAP_AND_RETURN(type) \
|
do { \
|
type val = 0; \
|
[self getReturnValue:&val]; \
|
return @(val); \
|
} while (0)
|
|
const char *returnType = self.methodSignature.methodReturnType;
|
// Skip const type qualifier.
|
if (returnType[0] == 'r') {
|
returnType++;
|
}
|
|
if (strcmp(returnType, @encode(id)) == 0 || strcmp(returnType, @encode(Class)) == 0 || strcmp(returnType, @encode(void (^)(void))) == 0) {
|
__autoreleasing id returnObj;
|
[self getReturnValue:&returnObj];
|
return returnObj;
|
} else if (strcmp(returnType, @encode(char)) == 0) {
|
WRAP_AND_RETURN(char);
|
} else if (strcmp(returnType, @encode(int)) == 0) {
|
WRAP_AND_RETURN(int);
|
} else if (strcmp(returnType, @encode(short)) == 0) {
|
WRAP_AND_RETURN(short);
|
} else if (strcmp(returnType, @encode(long)) == 0) {
|
WRAP_AND_RETURN(long);
|
} else if (strcmp(returnType, @encode(long long)) == 0) {
|
WRAP_AND_RETURN(long long);
|
} else if (strcmp(returnType, @encode(unsigned char)) == 0) {
|
WRAP_AND_RETURN(unsigned char);
|
} else if (strcmp(returnType, @encode(unsigned int)) == 0) {
|
WRAP_AND_RETURN(unsigned int);
|
} else if (strcmp(returnType, @encode(unsigned short)) == 0) {
|
WRAP_AND_RETURN(unsigned short);
|
} else if (strcmp(returnType, @encode(unsigned long)) == 0) {
|
WRAP_AND_RETURN(unsigned long);
|
} else if (strcmp(returnType, @encode(unsigned long long)) == 0) {
|
WRAP_AND_RETURN(unsigned long long);
|
} else if (strcmp(returnType, @encode(float)) == 0) {
|
WRAP_AND_RETURN(float);
|
} else if (strcmp(returnType, @encode(double)) == 0) {
|
WRAP_AND_RETURN(double);
|
} else if (strcmp(returnType, @encode(BOOL)) == 0) {
|
WRAP_AND_RETURN(BOOL);
|
} else if (strcmp(returnType, @encode(char *)) == 0) {
|
WRAP_AND_RETURN(const char *);
|
} else if (strcmp(returnType, @encode(void)) == 0) {
|
return RACUnit.defaultUnit;
|
} else {
|
NSUInteger valueSize = 0;
|
NSGetSizeAndAlignment(returnType, &valueSize, NULL);
|
|
unsigned char valueBytes[valueSize];
|
[self getReturnValue:valueBytes];
|
|
return [NSValue valueWithBytes:valueBytes objCType:returnType];
|
}
|
|
return nil;
|
|
#undef WRAP_AND_RETURN
|
}
|
|
@end
|