Skip to content

Instantly share code, notes, and snippets.

@mikeash
Created June 21, 2014 21:36
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save mikeash/861217e2c924941484a7 to your computer and use it in GitHub Desktop.
Save mikeash/861217e2c924941484a7 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],
};
}
typedef __unsafe_unretained NSDictionary *JSONDictionary;
typedef __unsafe_unretained NSArray *JSONArray;
typedef __unsafe_unretained NSString *JSONString;
void JSONDecodeF(void *target, id inJSON, 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 = @{
@"JSONString": [NSString class],
@"JSONDictionary": [NSDictionary class],
@"JSONArray": [NSArray class],
@"double": [NSNumber class]
};
Class class = typeMap[typeName];
if(class == Nil) {
NSLog(@"Unknown JSON type name %@", typeName);
abort();
}
__autoreleasing id value = inJSON[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 {
void *voidValue = (__bridge void *)value;
memcpy(cursor, &voidValue, sizeof(value));
cursor += sizeof(value);
}
}
}
#define JSONDecode(varname, inJSON, fields) \
struct { fields } varname; JSONDecodeF(&varname, inJSON, @#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();
JSONDecode(decoded, dict,
JSONString string;
double number;
JSONDictionary dictionary;
);
NSLog(@"%@ %f", decoded.string, decoded.number);
JSONDecode(innerDecoded, decoded.dictionary,
JSONString string;
JSONArray array;
);
NSLog(@"%@ %@", innerDecoded.string, innerDecoded.array);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment