Skip to content

Instantly share code, notes, and snippets.

@samsonjs
Forked from mikeash/gist:861217e2c924941484a7
Last active August 29, 2015 14:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save samsonjs/68d132908809e017eebf to your computer and use it in GitHub Desktop.
Save samsonjs/68d132908809e017eebf to your computer and use it in GitHub Desktop.
#import <Foundation/Foundation.h>
NSDictionary *TestD(void) {
return @{
@"string" : @"abc",
@"number" : @42,
@"dictionary" : @{
@"string" : @"abcdef",
@"array" : @[ @"a", @2 ]
},
@"data" : [@"hello" dataUsingEncoding: NSUTF8StringEncoding],
@"date" : [NSDate dateWithTimeIntervalSince1970: 42],
@"boolean" : @YES
};
}
typedef __unsafe_unretained NSDictionary *Dict;
typedef __unsafe_unretained NSArray *Array;
typedef __unsafe_unretained NSString *String;
void DeconstructF(void *target, id inDict, NSString *fieldsString, void(^Error)(NSString *fieldName, Class desiredType, Class actualType)) {
char *cursor = target;
NSArray *fieldsStrings = [fieldsString componentsSeparatedByString: @";"];
for (NSString *fieldString in fieldsStrings) {
NSString *trimmed = [fieldString stringByTrimmingCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSArray *split = [trimmed componentsSeparatedByCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *typeName = [split firstObject];
NSString *fieldName = [split lastObject];
if ([typeName length] == 0) continue;
NSDictionary *typeMap = @{
@"String": [NSString class],
@"Dict": [NSDictionary class],
@"Array": [NSArray class],
@"double": [NSNumber class],
@"BOOL": [NSNumber class]
};
Class class = typeMap[typeName];
if (class == Nil) {
NSLog(@"Unknown type name %@", typeName);
abort();
}
__autoreleasing id value = inDict[fieldName];
if (![value isKindOfClass: class]) {
Error(fieldName, class, [value classForCoder]);
}
if ([typeName isEqual: @"double"]) {
double primitiveValue = [value doubleValue];
memcpy(cursor, &primitiveValue, sizeof(primitiveValue));
cursor += sizeof(primitiveValue);
}
else if ([typeName isEqual: @"boolean"]) {
double primitiveValue = [value boolValue];
memcpy(cursor, &primitiveValue, sizeof(primitiveValue));
cursor += sizeof(primitiveValue);
}
else {
void *voidValue = (__bridge void *)value;
memcpy(cursor, &voidValue, sizeof(value));
cursor += sizeof(value);
}
}
}
#define Deconstruct(varname, inDict, fields) \
struct { fields } varname; DeconstructF(&varname, inDict, @#fields, ^(NSString *fieldName, Class desiredType, Class actualType){ NSLog(@"Error: %@ is %@ but expected %@", fieldName, actualType, desiredType); })
int main(int argc, char **argv) {
@autoreleasepool {
NSDictionary *dict = TestD();
Deconstruct(decoded, dict,
String string;
double number;
BOOL boolean;
Dict dictionary;
);
NSLog(@"%@ %f %@", decoded.string, decoded.number, decoded.boolean ? @"YES" : @"NO");
Deconstruct(innerDecoded, decoded.dictionary,
String string;
Array array;
);
NSLog(@"%@ %@", innerDecoded.string, innerDecoded.array);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment